Example #1
0
def breakDownWallet(walletPath, fragSize):
    print 'breaking down wallet in packs of %d addresses' % fragSize
    print 'reading wallet'
    theWallet = PyBtcWallet().readWalletFile(walletPath)

    nAddresses = len(theWallet.addrMap)

    addrIndex = 0
    wltIndex = 1

    if walletPath[-7:] == '.wallet':
        newDir = walletPath[:-7]
    else:
        newDir = os.path.dirname(walletPath)

    if not os.path.exists(newDir):
        os.mkdir(newDir)

    rootAddr = theWallet.addrMap['ROOT']
    withEncrypt = theWallet.useEncryption
    addrIter = theWallet.addrMap.iteritems()

    while nAddresses > 0:

        print 'breaking down wallet from address #%d to #%d' % (
            addrIndex, addrIndex + fragSize - 1)
        nAddresses -= fragSize

        newWalletPath = os.path.join(newDir,
                                     'armory_wlt_%05d_.wallet' % wltIndex)
        wltIndex += 1

        walletFragment = PyBtcWallet()
        createNewWallet(walletFragment, rootAddr, newWalletPath, withEncrypt,
                        theWallet.kdf)

        fileData = BinaryPacker()
        i = 0

        try:
            while i < fragSize:
                addrItem = addrIter.next()[1]
                addrItem.chainIndex = -2

                fileData.put(
                    BINARY_CHUNK,
                    '\x00' + addrItem.addrStr20 + addrItem.serialize())
                #walletFragment.walletFileSafeUpdate([[WLT_UPDATE_ADD, \
                #WLT_DATATYPE_KEYDATA, addrItem.addrStr20, addrItem]])
                i += 1

        except StopIteration:
            pass

        walletFile = open(newWalletPath, 'ab')
        walletFile.write(fileData.getBinaryString())
        walletFile.close()

        addrIndex += i
    print 'Done'
def breakDownWallet(walletPath, fragSize):
   print 'breaking down wallet in packs of %d addresses' % fragSize
   print 'reading wallet'
   theWallet = PyBtcWallet().readWalletFile(walletPath)
   
   nAddresses = len(theWallet.addrMap)
   
   addrIndex = 0
   wltIndex = 1

   if walletPath[-7:] == '.wallet':
      newDir = walletPath[:-7]
   else:
      newDir = os.path.dirname(walletPath)
      
   if not os.path.exists(newDir):
      os.mkdir(newDir)
      
   rootAddr = theWallet.addrMap['ROOT']
   withEncrypt = theWallet.useEncryption
   addrIter = theWallet.addrMap.iteritems()
   
   while nAddresses > 0 :
      
      print 'breaking down wallet from address #%d to #%d' % (addrIndex, addrIndex +fragSize-1)
      nAddresses -= fragSize

      
      newWalletPath = os.path.join(newDir, 'armory_wlt_%05d_.wallet' % wltIndex)
      wltIndex += 1
      
      walletFragment = PyBtcWallet()
      createNewWallet(walletFragment, rootAddr, newWalletPath, withEncrypt, theWallet.kdf) 
   
      fileData = BinaryPacker()
      i=0
      
      try:
         while i < fragSize:
            addrItem = addrIter.next()[1]
            addrItem.chainIndex = -2
            
            fileData.put(BINARY_CHUNK, '\x00' + addrItem.addrStr20 + addrItem.serialize())
            #walletFragment.walletFileSafeUpdate([[WLT_UPDATE_ADD, \
                           #WLT_DATATYPE_KEYDATA, addrItem.addrStr20, addrItem]])
            i += 1
            
      except StopIteration:
         pass
      
      walletFile = open(newWalletPath, 'ab')
      walletFile.write(fileData.getBinaryString())
      walletFile.close()      
      
      addrIndex += i
   print 'Done'
def getTxInStr(txInPrevHash, txInPrevTxOutHashIdx, txInScrLen, txInScr, \
               txInSeqNum):
    '''Function that creates a transaction input from the function inputs.'''
    txInBin = BinaryPacker()
    txInBin.put(BINARY_CHUNK, txInPrevHash)
    txInBin.put(UINT32, txInPrevTxOutHashIdx)
    txInBin.put(VAR_INT, txInScrLen)
    txInBin.put(BINARY_CHUNK, txInScr)
    txInBin.put(UINT32, txInSeqNum)
    return txInBin.getBinaryString()
def getTxOutStr(txOutVal, txOutScrLen, txOutScr):
    '''Function that creates a transaction output from the function inputs.'''
    txOutBin = BinaryPacker()
    txOutBin.put(UINT64, txOutVal)
    txOutBin.put(VAR_INT, txOutScrLen)
    txOutBin.put(BINARY_CHUNK, txOutScr)
    return txOutBin.getBinaryString()
 def testBinaryPacker(self):
    UNKNOWN_TYPE = 100
    TEST_FLOAT = 1.23456789
    TEST_UINT = 0xff
    TEST_INT = -1
    TEST_VARINT = 78
    TEST_STR = 'abc'
    TEST_BINARY_PACKER_STR = hex_to_binary('ffff00ff000000ff00000000000000ffffffffffffffffffffffffffffff4e0361626352069e3fffffffffffff00')
    FS_FOR_3_BYTES = '\xff\xff\xff'
    bp = BinaryPacker()
    bp.put(UINT8, TEST_UINT)
    bp.put(UINT16, TEST_UINT)
    bp.put(UINT32, TEST_UINT)
    bp.put(UINT64, TEST_UINT)
    bp.put(INT8, TEST_INT)
    bp.put(INT16, TEST_INT)
    bp.put(INT32, TEST_INT)
    bp.put(INT64, TEST_INT)
    bp.put(VAR_INT, TEST_VARINT)
    bp.put(VAR_STR, TEST_STR)
    bp.put(FLOAT, TEST_FLOAT)
    bp.put(BINARY_CHUNK, FS_FOR_3_BYTES)
    bp.put(BINARY_CHUNK, FS_FOR_3_BYTES, 4)
    self.assertRaises(PackerError, bp.put, UNKNOWN_TYPE, TEST_INT)
    self.assertRaises(PackerError, bp.put, BINARY_CHUNK, FS_FOR_3_BYTES, 2)
    self.assertEqual(bp.getSize(), len(TEST_BINARY_PACKER_STR))
    ts = bp.getBinaryString()
    self.assertEqual(ts, TEST_BINARY_PACKER_STR)
    bu = BinaryUnpacker(ts)
    self.assertEqual(bu.get(UINT8), TEST_UINT)
    self.assertEqual(bu.get(UINT16), TEST_UINT)
    self.assertEqual(bu.get(UINT32), TEST_UINT)
    self.assertEqual(bu.get(UINT64), TEST_UINT)
    self.assertEqual(bu.get(INT8), TEST_INT)
    self.assertEqual(bu.get(INT16), TEST_INT)
    self.assertEqual(bu.get(INT32), TEST_INT)
    self.assertEqual(bu.get(INT64), TEST_INT)
    self.assertEqual(bu.get(VAR_INT), TEST_VARINT)
    self.assertEqual(bu.get(VAR_STR), TEST_STR)
    self.assertAlmostEqual(bu.get(FLOAT), TEST_FLOAT, 2)
    self.assertEqual(bu.get(BINARY_CHUNK, 3), FS_FOR_3_BYTES)
    self.assertEqual(bu.get(BINARY_CHUNK, 4), FS_FOR_3_BYTES+"\x00")
    self.assertRaises(UnpackerError, bu.get, BINARY_CHUNK, 1)
    self.assertRaises(UnpackerError, bu.get, UNKNOWN_TYPE)
    self.assertRaises(UnpackerError, bu.get, BINARY_CHUNK, 1)
def processTxOutScr(txOutScr, blkHash, blkPos, txIdx, txOutIdx):
    '''Function processing a TxOut script.'''
    # Proceed only if there's data to read.
    retVal = txOutScr
    txOutScrUnpack = BinaryUnpacker(txOutScr)
    txOutAddress = BinaryPacker()
    txType = TxType.unknownTx
    txOutScrSize = txOutScrUnpack.getRemainingSize()

    if(txOutScrSize > 0):
        # Read the initial byte and determine what TxOut type it is.
        initByte = txOutScrUnpack.get(BINARY_CHUNK, 1)

        # 0x21/0x41 = Pay2PubKey
        if(initByte == '\x21' or initByte == '\x41'):
            # Make sure it's a valid pub key before declaring it valid.
            pkLen = isPubKey(txOutScrUnpack)
            if(pkLen != 0):
                # Save the pub key.
                txOutKey = txOutScrUnpack.get(BINARY_CHUNK, pkLen)
                txOutAddress.put(BINARY_CHUNK, txOutKey)
                txType = TxType.p2pKey

        # OP_DUP = Pay2PubKeyHash
        elif(initByte == OP_DUP):
            # HACK ALERT: Some bright bulb has created OP_* TxOuts that have
            # nothing but the OP_* code. Check the remaining size upfront.
            # (Checking after every read is more robust, really. I'm just lazy
            # and don't want to retrofit this chunk of code. :) )
            if(txOutScrUnpack.getRemainingSize() > 0):
                hashByte = txOutScrUnpack.get(BINARY_CHUNK, 1)
                if(hashByte == OP_HASH160):
                    hashSize = txOutScrUnpack.get(BINARY_CHUNK, 1)
                    hashRemSize = txOutScrUnpack.getRemainingSize()
                    if(hashSize == '\x14' and \
                       hashRemSize >= binary_to_int(hashSize)):
                        txOutHash = txOutScrUnpack.get(BINARY_CHUNK, \
                                                       binary_to_int(hashSize))
                        # Save the hash.
                        txOutAddress.put(BINARY_CHUNK, txOutHash)
                        eqVerByte = txOutScrUnpack.get(BINARY_CHUNK, 1)
                        if(eqVerByte == OP_EQUALVERIFY):
                            checkSigByte = txOutScrUnpack.get(BINARY_CHUNK, 1)
                            if(checkSigByte == OP_CHECKSIG):
                                txType = TxType.p2pHash

        # OP_HASH160 = Pay2ScriptHash
        elif(initByte == OP_HASH160):
            hashSize = txOutScrUnpack.get(BINARY_CHUNK, 1)
            hashRemSize = txOutScrUnpack.getRemainingSize()
            if(hashSize == '\x14' and hashRemSize >= binary_to_int(hashSize)):
                txOutHash = txOutScrUnpack.get(BINARY_CHUNK, \
                                               binary_to_int(hashSize))
                # Save the hash.
                txOutAddress.put(BINARY_CHUNK, txOutHash)
                eqByte = txOutScrUnpack.get(BINARY_CHUNK, 1)
                if(eqByte == OP_EQUAL):
                    txType = TxType.p2sh

        # OP_1/2/3 = MultiSig
        elif(initByte == OP_1 or initByte == OP_2 or initByte == OP_3):
            validKeys = True
            readByte = 0
            numKeys = 0

            # HACK ALERT 1: Some scripts are weird and initially appear to be
            # multi-sig but really aren't. We should compensate. One particular
            # way is to require at least 36 bytes (assume 1-of-1 w/ compressed
            # key) beyond the initial byte.
            #
            # HACK ALERT 2: There are some multisig TxOuts that, for unknown
            # reasons have things like compressed keys that where the first byte
            # is 0x00, not 0x02 or 0x03. For now, we just mark them as unknown
            # Tx and move on.
            if(txOutScrUnpack.getRemainingSize() >= 36):
                readByte = txOutScrUnpack.get(BINARY_CHUNK, 1)
                while((readByte == '\x21' or readByte == '\x41') and numKeys < 3
                       and validKeys == True):
                    pkLen = isPubKey(txOutScrUnpack)
                    if(pkLen != 0):
                        txOutKey = txOutScrUnpack.get(BINARY_CHUNK, pkLen)
                        # Save the key.
                        txOutAddress.put(BINARY_CHUNK, txOutKey)
                        numKeys += 1
                        readByte = txOutScrUnpack.get(BINARY_CHUNK, 1)
                    else:
                        validKeys = False
            else:
                validKeys = False
            if(validKeys == True):
                if((readByte == OP_1 or readByte == OP_2 or readByte == OP_3) \
                    and binary_to_int(initByte) <= binary_to_int(readByte)):
                    cmsByte = txOutScrUnpack.get(BINARY_CHUNK, 1)
                    if(cmsByte == OP_CHECKMULTISIG):
                        txType = TxType.multiSig

        # OP_RETURN = Arbitrary data attached to a Tx.
        # Official as of BC-Core 0.9. https://bitcoinfoundation.org/blog/?p=290
        # and https://github.com/bitcoin/bitcoin/pull/2738 have the details of
        # the initial commit, with https://github.com/bitcoin/bitcoin/pull/3737
        # having the revision down to 40 bytes.
        elif(initByte == OP_RETURN):
            # If the 1st byte is OP_RETURN, as of BC-Core v0.9, there can be
            # arbitrary data placed afterwards. This makes the TxOut immediately
            # prunable, meaning it can never be used as a TxIn. (It can still be
            # spent, mind you.) The final BC-Core 0.9 only accepts <=40 bytes,
            # but preview versions accepted <=80. In theory, any amount of data
            # is valid, but miners won't accept non-standard amounts by default.
            #
            # Anyway, since it's arbitrary, we don't care what's present and
            # just assume it's valid. Save all the data as the TxOut address.
            opRetData = txOutScrUnpack.get(BINARY_CHUNK, \
                                           txOutScrUnpack.getRemainingSize())
            # Save the data.
            txOutAddress.put(BINARY_CHUNK, opRetData)
            txType = TxType.opReturn

        # Everything else isn't standard. For now, we'll do nothing.
        # else:
        #     print("DEBUG: 1st BYTE (TxOut) IS TOTALLY UNKNOWN!!! BYTE={0}".format(binary_to_hex(initByte)))

    # Could it be that there is no TxOut script? Is this legal? Let's take a
    # peek and write some debug code.
    else:
        print("DEBUG: At block {0}, we have an empty TxOut script!".format(blkPos))

    # If we have a known TxOut type, we'll return an address instead of the
    # entire TxOut script. Note that it's unlikely but possible that an address
    # value for, say, OP_RETURN could match a pub key hash. In production code,
    # we'd want to add extra data to ensure that no collisions have occurred
    # (e.g., 2 different addresses are sharing a common balance), or possibly
    # use a different approach altogether.
    if(txType != TxType.unknownTx):
        retVal = txOutAddress.getBinaryString()
        if(txType == TxType.p2pKey):
            step1 = hash160(retVal)
            step2 = hash160_to_addrStr(step1)
            retVal = base58_to_binary(step2)
        elif(txType == TxType.p2pHash):
            step1 = hash160_to_addrStr(retVal)
            retVal = base58_to_binary(step1)

    return retVal
    def testBinaryPacker(self):
        UNKNOWN_TYPE = 100
        TEST_FLOAT = 1.23456789
        TEST_UINT = 0xff
        TEST_INT = -1
        TEST_VARINT = 78
        TEST_STR = 'abc'
        TEST_BINARY_PACKER_STR = hex_to_binary(
            'ffff00ff000000ff00000000000000ffffffffffffffffffffffffffffff4e0361626352069e3fffffffffffff00'
        )
        FS_FOR_3_BYTES = '\xff\xff\xff'
        bp = BinaryPacker()
        bp.put(UINT8, TEST_UINT)
        bp.put(UINT16, TEST_UINT)
        bp.put(UINT32, TEST_UINT)
        bp.put(UINT64, TEST_UINT)
        bp.put(INT8, TEST_INT)
        bp.put(INT16, TEST_INT)
        bp.put(INT32, TEST_INT)
        bp.put(INT64, TEST_INT)
        bp.put(VAR_INT, TEST_VARINT)
        bp.put(VAR_STR, TEST_STR)
        bp.put(FLOAT, TEST_FLOAT)
        bp.put(BINARY_CHUNK, FS_FOR_3_BYTES)
        bp.put(BINARY_CHUNK, FS_FOR_3_BYTES, 4)
        self.assertRaises(PackerError, bp.put, UNKNOWN_TYPE, TEST_INT)
        self.assertRaises(PackerError, bp.put, BINARY_CHUNK, FS_FOR_3_BYTES, 2)
        self.assertEqual(bp.getSize(), len(TEST_BINARY_PACKER_STR))
        ts = bp.getBinaryString()
        self.assertEqual(ts, TEST_BINARY_PACKER_STR)
        bu = BinaryUnpacker(ts)
        self.assertEqual(bu.get(UINT8), TEST_UINT)
        self.assertEqual(bu.get(UINT16), TEST_UINT)
        self.assertEqual(bu.get(UINT32), TEST_UINT)
        self.assertEqual(bu.get(UINT64), TEST_UINT)
        self.assertEqual(bu.get(INT8), TEST_INT)
        self.assertEqual(bu.get(INT16), TEST_INT)
        self.assertEqual(bu.get(INT32), TEST_INT)
        self.assertEqual(bu.get(INT64), TEST_INT)
        self.assertEqual(bu.get(VAR_INT), TEST_VARINT)
        self.assertEqual(bu.get(VAR_STR), TEST_STR)
        self.assertAlmostEqual(bu.get(FLOAT), TEST_FLOAT, 2)
        self.assertEqual(bu.get(BINARY_CHUNK, 3), FS_FOR_3_BYTES)
        self.assertEqual(bu.get(BINARY_CHUNK, 4), FS_FOR_3_BYTES + "\x00")
        self.assertRaises(UnpackerError, bu.get, BINARY_CHUNK, 1)
        self.assertRaises(UnpackerError, bu.get, UNKNOWN_TYPE)
        self.assertRaises(UnpackerError, bu.get, BINARY_CHUNK, 1)


# Running tests with "python <module name>" will NOT work for any Armory tests
# You must run tests with "python -m unittest <module name>" or run all tests with "python -m unittest discover"
# if __name__ == "__main__":
#    unittest.main()
def getTxHash(txVer, numTxIn, txInList, numTxOut, txOutList, txLockTime):
    '''Function that creates a 2xSHA256 hash of a transaction.'''
    txHashBin = BinaryPacker()
    txHashBin.put(UINT32, txVer)
    txHashBin.put(VAR_INT, numTxIn)
    for txIn in txInList:
        txHashBin.put(BINARY_CHUNK, txIn)
    txHashBin.put(VAR_INT, numTxOut)
    for txOut in txOutList:
        txHashBin.put(BINARY_CHUNK, txOut)
    txHashBin.put(UINT32, txLockTime)
    return hash256(txHashBin.getBinaryString())
 def testBinaryPacker(self):
     UNKNOWN_TYPE = 100
     TEST_FLOAT = 1.23456789
     TEST_UINT = 0xff
     TEST_INT = -1
     TEST_VARINT = 78
     TEST_STR = 'abc'
     TEST_BINARY_PACKER_STR = hex_to_binary(
         'ffff00ff000000ff00000000000000ffffffffffffffffffffffffffffff4e0361626352069e3fffffffffffff00'
     )
     FS_FOR_3_BYTES = '\xff\xff\xff'
     bp = BinaryPacker()
     bp.put(UINT8, TEST_UINT)
     bp.put(UINT16, TEST_UINT)
     bp.put(UINT32, TEST_UINT)
     bp.put(UINT64, TEST_UINT)
     bp.put(INT8, TEST_INT)
     bp.put(INT16, TEST_INT)
     bp.put(INT32, TEST_INT)
     bp.put(INT64, TEST_INT)
     bp.put(VAR_INT, TEST_VARINT)
     bp.put(VAR_STR, TEST_STR)
     bp.put(FLOAT, TEST_FLOAT)
     bp.put(BINARY_CHUNK, FS_FOR_3_BYTES)
     bp.put(BINARY_CHUNK, FS_FOR_3_BYTES, 4)
     self.assertRaises(PackerError, bp.put, UNKNOWN_TYPE, TEST_INT)
     self.assertRaises(PackerError, bp.put, BINARY_CHUNK, FS_FOR_3_BYTES, 2)
     self.assertEqual(bp.getSize(), len(TEST_BINARY_PACKER_STR))
     ts = bp.getBinaryString()
     self.assertEqual(ts, TEST_BINARY_PACKER_STR)
     bu = BinaryUnpacker(ts)
     self.assertEqual(bu.get(UINT8), TEST_UINT)
     self.assertEqual(bu.get(UINT16), TEST_UINT)
     self.assertEqual(bu.get(UINT32), TEST_UINT)
     self.assertEqual(bu.get(UINT64), TEST_UINT)
     self.assertEqual(bu.get(INT8), TEST_INT)
     self.assertEqual(bu.get(INT16), TEST_INT)
     self.assertEqual(bu.get(INT32), TEST_INT)
     self.assertEqual(bu.get(INT64), TEST_INT)
     self.assertEqual(bu.get(VAR_INT), TEST_VARINT)
     self.assertEqual(bu.get(VAR_STR), TEST_STR)
     self.assertAlmostEqual(bu.get(FLOAT), TEST_FLOAT, 2)
     self.assertEqual(bu.get(BINARY_CHUNK, 3), FS_FOR_3_BYTES)
     self.assertEqual(bu.get(BINARY_CHUNK, 4), FS_FOR_3_BYTES + "\x00")
     self.assertRaises(UnpackerError, bu.get, BINARY_CHUNK, 1)
     self.assertRaises(UnpackerError, bu.get, UNKNOWN_TYPE)
     self.assertRaises(UnpackerError, bu.get, BINARY_CHUNK, 1)