def test_p2sh_address_creation(self): x1_first_btc_key = bip32_public_derivation(self.wallet.master_public_keys.get("x1/"), "", "/0/0/0") x2_first_btc_key = bip32_public_derivation(self.wallet.master_public_keys.get("x2/"), "", "/0/0/0") x_pubkeys = [x1_first_btc_key, x2_first_btc_key] raw_pubkeys = map( lambda x: deserialize_xkey(x)[4], x_pubkeys ) pubkeys = map( lambda x: x.encode('hex'), raw_pubkeys ) # Compare redeem script to manually calculated one redeem_script = Transaction.multisig_script(sorted(pubkeys), 2) self.assertEqual('522102ee780aa224c9fe54caff984205077b7cca08ced3188a3f3c639d83deda6b9a592103124429ddbed55593d0abea0d0d3d283eca4546e40017b2945f4666c561b494ba52ae', redeem_script) p2sh_addr = hash_160_to_bc_address( hash_160(redeem_script.decode('hex')), self.wallet.active_chain.p2sh_version ) self.assertEqual('3MqemPAHZDGLr537QBvU7i4dRFY3Xvad7X', p2sh_addr) # switch chains self._switch_chain("MZC") x1_first_mzc_key = bip32_public_derivation(self.wallet.master_public_keys.get("x1/"), "", "/13/0/0") x2_first_mzc_key = bip32_public_derivation(self.wallet.master_public_keys.get("x2/"), "", "/13/0/0") x_pubkeys = [x1_first_mzc_key, x2_first_mzc_key] raw_pubkeys = map( lambda x: deserialize_xkey(x)[4], x_pubkeys ) pubkeys = map( lambda x: x.encode('hex'), raw_pubkeys ) # Compare redeem script to manually calculated one redeem_script = Transaction.multisig_script(sorted(pubkeys), 2) self.assertEqual('5221027bdb7f5c42096580442e63235434bcc9ddf9689bbeb917705cd0edf9c6e264292102919725862f59a43274443ea11d7a8e25c15147213dcb6186c24d8629d37d6d8d52ae', redeem_script) p2sh_addr = hash_160_to_bc_address( hash_160(redeem_script.decode('hex')), self.wallet.active_chain.p2sh_version ) self.assertEqual('4jjXnsGuWLH3YgnagWH12kK7HjDtsBv8SQ', p2sh_addr)
def createTransaction(self, password, destList): """Create a new transaction and send it to the RelayNode destList is a list of tuples Each tuples is like : (str_address, value) The last transaction is the rest of the wallet send to the new user address """ self.checkUpdate() newAddr = Address() newAddr.encryptPrivateKey(password) total = sum([i[1] for i in destList]) if total <= self.count: destList.append((str(newAddr), (self.count - total))) transac = Transaction(self.addr.public(), destList) self.addr.decryptPrivateKey(password) transac.sign(self.addr) debug('valid: ' + ('True' if transac.is_signed() else 'False')) self.addr.encryptPrivateKey(password) if not self.relay.submit_transaction(transac): return False self.addrList.append(newAddr) self.addr = newAddr add_address(self.user_ID, self.addr, len(self.addrList) - 1) return True else: return False
def test_deserialize(self): tx = Transaction(self.coinstake_tx) tx.deserialize() self.assertEquals(tx.output_value(), 1437000000) self.assertEquals(tx.version, 2) self.assertEquals(tx.time, 1430932848) self.assertEquals(tx.clamspeech, 'https://Just-Dice.com')
def handle_request(self, request): try: request_type = request.get('type') if request_type not in self.no_auth_check_handlers: username = request.get('auth', {}).get('username') token = request.get('auth', {}).get('auth_token') if not username or not token: return construct_result(400, 'Bad request') with Transaction() as tr: try: user = User.read_by_name(tr.cursor, username) except ItemNotFoundError: return construct_result(404, 'User not found') if not self.auth_handler.verify_auth_token(user.user_id, token): return construct_result(403, 'Bad auth token, you should sign in') self.context['user_id'] = user.user_id return self.type_to_handler.get(request_type, lambda _: construct_result(400, 'Bad request'))(request) except KeyboardInterrupt: raise except Exception as e: logging.exception('Unhandled exception during request handling occured: {}'.format(e)) return construct_result(500, 'Error occured')
def transfer(bc, relay, from_addr, to_addr, amount): f = get_address(from_addr) if f is None: exit('no address '+str(from_addr)+' in database') total = bc.get_amount_of_address(f) if total < amount: exit('not enough money for this transfer') pwd = getpass.getpass() while not f.decryptPrivateKey(pwd): print('Invalid password') pwd = getpass.getpass() receivers = [(to_addr, amount)] if total > amount: new = Address() new.encryptPrivateKey(pwd) db.add_address('client', new, 0) print('created new address '+str(new)+' to receive remaining funds') receivers.append((str(new), total - amount)) t = Transaction(f, receivers) if relay.submit_transaction(t): print('transaction sent to the network') else: print('error sending transaction')
def __init__(self, seed, *args): self.seed = seed self.wallet = Wallet(utils.hash(str(self.seed))) self.neighbours = set() self.DAG = {} root_transaction = Transaction('0000', 'root', 25000000000) self.attach_transaction(root_transaction, ['root'])
def create_tx(self): tx = Transaction(version=self.tx_version, sig_hash_type=self.sig_hash_type, sig_hash_type_pre_image=self.sig_hash_type_pre_image, sign_style=self.sign_type) keys = [] for utxo in self.utxos: pub_key = utxo.private_key.create_pub_key() keys.append(KeyPair(utxo.private_key, pub_key)) tx_input = TransactionInput(utxo.tx_hash, utxo.index, utxo.address, get_spend_type(utxo.address), prev_amount=utxo.amount_btc, pub_key=pub_key) tx.add_inputs(tx_input) for destination in self.destinations: tx_output = TransactionOutput( btc_to_satoshis(destination.amount_btc), destination.address, get_spend_type(destination.address)) tx.add_outputs(tx_output) signed = tx.sign(*keys) return signed.serialize()
def make_transaction(self, receiving_addr, value): ''' 1. Pick at least two transactions in Tangle to confirm 2. Check picked transactions for conflict 3. Approve non conflicting transactions 4. Perform proof of work 5. Send transaction to tangle ''' confirmed_transactions = self.confirm_transactions() if len(confirmed_transactions) >= 2: proof_of_work = self.proof_of_work(''.join(confirmed_transactions)) new_transaction = Transaction(self.wallet.generate_address(), receiving_addr, value) new_transaction.pow = proof_of_work return self.attach_transaction(new_transaction, confirmed_transactions) return {'msg': 'transaction failed'}
def construct_follows_list_response(follows, followers_mode=False): res = [] for follow in follows: with Transaction() as tr: try: user_id = follow.user_id if not followers_mode else follow.follower_id res.append(User.read_by_pk(tr.cursor, user_id).username) except ItemNotFoundError: continue return res
def handle_post(self, request): text = request.get('text') if not text: return construct_result(400, 'Bad request') ts = int(time.time()) with Transaction() as tr: Post(self.context['user_id'], None, text, ts).create_me(tr.cursor) return construct_result()
def post_transaction(self, json): t = Transaction.fromJson(json) if t is None: debug('JSON error') self.no_response(400) # Bad Request elif not t.is_valid(self.server.blockchain): debug('invalid blockchain transaction') self.no_response(400) # Bad Request else: self.server.transactions.append(t) self.no_response(200) # OK self.broadcast_transaction(t)
def test_pending_transactions(self): receiver = generate_key() tx = Transaction(None, txtype=TxType.COINBASE) tx.add_out(10, receiver.publickey()) blockchain = Blockchain() blockchain.add(tx) pending_tx = blockchain.get_pending_transactions() self.assertEqual(len(filter(lambda x: tx.hash, pending_tx)), 1) miner = Miner(blockchain) miner.reward_addr = receiver.publickey() newb = miner._mine() pending_tx = blockchain.get_pending_transactions() self.assertEqual(len(filter(lambda x: tx.hash, pending_tx)), 0) self.assertEqual(len(filter(lambda x: tx.hash, newb.transactions)), 2)
def __init__(self, isgenesis=True, *args): # represent the "sites" containing transactions # self.tngl = nx.DiGraph() if isgenesis: self.DAG = OrderedDict() genesis_tx = Transaction('genesis_address', 'genesis_address', 21000000) genesis_tx_key = self.attach_transaction(genesis_tx, ['genesis_tx']) founding_txA = Transaction('genesis_address', 'founderA_address', 7000000) self.attach_transaction(founding_txA, [genesis_tx_key]) founding_txB = Transaction('genesis_address', 'founderB_address', 7000000) self.attach_transaction(founding_txB, [genesis_tx_key]) else: print "[+] Genesis tangle is already done, connect and sync from neighbours"
def construct_posts_list_response(posts): res = [] for post in posts: post_dict = post.to_dict() with Transaction() as tr: try: post_dict['username'] = User.read_by_pk( tr.cursor, post_dict.pop('user_id')).username except ItemNotFoundError: continue res.append(post_dict) return res
def transaction_submit(): """Submit a new transaction to the pool.""" try: if not request.json: abort(400, "Invalid transaction") tx = Transaction.deserialise_dict(request.json) tx.validate(CHAIN.q) CHAIN.q.add_transaction_to_pending(tx) except TransactionValidationError as exc: abort(400, "Invalid transaction: {}".format(exc)) except BlockChainError: abort(500, "Blockchain error")
def handle_get_user_posts(self, request): username = request.get('username') if not username: return construct_result(400, 'Bad request') with Transaction() as tr: try: user = User.read_by_name(tr.cursor, username) except ItemNotFoundError: return construct_result(404, 'User not found') posts = Post.get_user_posts(tr.cursor, user.user_id) return construct_result(200, construct_posts_list_response(posts))
def handle_get_following_users(self, request): username = request.get('username') if not username: return construct_result(400, 'Bad request') with Transaction() as tr: try: user = User.read_by_name(tr.cursor, username) except ItemNotFoundError: return construct_result(404, 'User not found') follows = Follow.get_following_users(tr.cursor, user.user_id) return construct_result(200, construct_follows_list_response(follows, followers_mode=True))
def handle_follow(self, request): username_to_follow = request.get('username_to_follow') if not username_to_follow: return construct_result(400, 'Bad request') with Transaction() as tr: try: user_to_follow = User.read_by_name(tr.cursor, username_to_follow) except ItemNotFoundError: return construct_result(404, 'User not found') Follow(None, user_to_follow.user_id, self.context['user_id']).create_me(tr.cursor) return construct_result()
def fromJson(json_data): try: data = json.loads(json_data) b = Block(data["previous_hash"], data["miner_address"]) ts = [] for t in data["transactions"]: ts.append(Transaction.fromJson(t)) b.set_transactions(ts) b.set_proof(data["proof"]) return b # JSON ValueError for decode # KeyError if no accessed key except (ValueError, KeyError, TypeError): return None
def maketx(inputs, outputs): """ Make a transaction from the given inputs and outputs list. Saves the serialized tx to `alltxes` and returns the key (its txid). """ tx = Transaction.from_io(inputs, outputs) txid = tx.txid() raw = str(tx) # ensure we work with serialized version. #txid = Transaction(raw).txid() # re-deserialize to make sure we get the right txid alltxes[txid] = raw print("Generated %.10s... (%d -> %d)" % (txid, len(inputs), len(outputs))) return txid
def handle_like(self, request): post_id = request.get('post_id') if not post_id: return construct_result(400, 'Bad request') with Transaction() as tr: try: post = Post.read_by_pk(tr.cursor, post_id) except ItemNotFoundError: return construct_result(404, 'Post not found') post.likes += 1 post.update_me(tr.cursor) return construct_result()
def handle_signin(self, request): username = request.get('username') password = request.get('password') if not username or not password: return construct_result(400, 'Bad request') with Transaction() as tr: try: user = User.read_by_name(tr.cursor, username) except ItemNotFoundError: return construct_result(404, 'User not found') if not self.auth_handler.verify_password(password, user.password_key): return construct_result(400, 'Bad password') return construct_result(200, {'auth_token': self.auth_handler.get_auth_token(user.user_id)})
def get_transactions(self): """send GET request to relay/transactions/ and parse it """ r = get_request(self.url+'transactions/') if r is None: return None if not r.status_code == 200: return None try: json_ts = r.json() except ValueError: return None ts = [] for json in json_ts: t = Transaction.fromJson(json) if not t is None: ts.append(t) return ts
def handle_signup(self, request): username = request.get('username') password = request.get('password') if not username or not password: return construct_result(400, 'Bad request') with Transaction() as tr: no_users = False try: user = User.read_by_name(tr.cursor, username) except ItemNotFoundError: no_users = True if not no_users: return construct_result(400, 'User already exists') User(None, username, self.auth_handler.get_password_key(password)).create_me(tr.cursor) return construct_result()
def handle_admin_info(self, request): with Transaction() as tr: try: user = User.read_by_pk(tr.cursor, self.context['user_id']) except ItemNotFoundError: return construct_result(404, 'User not found') if not user.is_admin: return construct_result(403, 'Access denied') users = User.read_all(tr.cursor) posts = Post.read_all(tr.cursor) follows = Follow.read_all(tr.cursor) return construct_result( 200, { 'users': [user.to_dict() for user in users], 'posts': [post.to_dict() for post in posts], 'folows': [follow.to_dict() for follow in follows], } )
def create_new_block(self): """ Create a fresh new block that contains all valid pending transactions. """ newb = Block(self.blockchain.top().hash) newb.index = self.blockchain.top().index + 1 newb.transactions.extend(self.blockchain.get_pending_transactions()) tx = Transaction(None, txtype=TxType.COINBASE) tx.add_out(MINING_REWARD, self.reward_addr) tx.finalize() newb.transactions.append(tx) return newb
def _test_fraudulent_tx(self, victim, blockchain): """ Try transaction from somebody else's "wallet" """ miner_key = generate_key() perpetrator = generate_key() utxo = blockchain.scan_unspent_transactions(victim.publickey()) perpetrator_owns = blockchain.scan_unspent_transactions( perpetrator.publickey()) self.assertEqual(len(perpetrator_owns), 0) # Sanity check # Let's handcraft tx that tries to steal victim's coins. tx = Transaction(perpetrator) # Sign it with random key utxo = blockchain.scan_unspent_transactions( victim.publickey()) # Get victim's utxo debit = sum(map(lambda x: x['value'], utxo)) for credit in utxo: tx.add_in(credit['hash'], sign(perpetrator, credit['hash']), victim.publickey(), credit['value']) tx.add_out(debit, perpetrator.publickey()) try: blockchain.add(tx) self.fail("Should've thrown UnauthorizedTxException") except UnauthorizedTxException: pass miner = Miner(blockchain) miner.reward_addr = miner_key.publickey() _ = miner._mine() perpetrator_owns = blockchain.scan_unspent_transactions( perpetrator.publickey()) # Should own nothing. This tx should've failed. self.assertEqual(len(perpetrator_owns), 0)
def test_sending_between_p2wsh_2of3_and_p2wsh_p2sh_2of2(self, mock_write): wallet1a = WalletIntegrityHelper.create_multisig_wallet( keystore.from_seed( 'bitter grass shiver impose acquire brush forget axis eager alone wine silver', '', True), keystore.from_xpub( 'Vpub5fcdcgEwTJmbmqAktuK8Kyq92fMf7sWkcP6oqAii2tG47dNbfkGEGUbfS9NuZaRywLkHE6EmUksrqo32ZL3ouLN1HTar6oRiHpDzKMAF1tf' ), keystore.from_xpub( 'Vpub5fjkKyYnvSS4wBuakWTkNvZDaBM2vQ1MeXWq368VJHNr2eT8efqhpmZ6UUkb7s2dwCXv2Vuggjdhk4vZVyiAQTwUftvff73XcUGq2NQmWra' ), gap_limit=2) wallet1b = WalletIntegrityHelper.create_multisig_wallet( keystore.from_seed( 'snow nest raise royal more walk demise rotate smooth spirit canyon gun', '', True), keystore.from_xpub( 'Vpub5fjkKyYnvSS4wBuakWTkNvZDaBM2vQ1MeXWq368VJHNr2eT8efqhpmZ6UUkb7s2dwCXv2Vuggjdhk4vZVyiAQTwUftvff73XcUGq2NQmWra' ), keystore.from_xpub( 'Vpub5gSKXzxK7FeKQedu2q1z9oJWxqvX72AArW3HSWpEhc8othDH8xMDu28gr7gf17sp492BuJod8Tn7anjvJrKpETwqnQqX7CS8fcYyUtedEMk' ), gap_limit=2) # ^ third seed: hedgehog sunset update estate number jungle amount piano friend donate upper wool wallet2a = WalletIntegrityHelper.create_multisig_wallet( # bip39: finish seminar arrange erosion sunny coil insane together pretty lunch lunch rose, der: m/1234'/1'/0', p2wsh-p2sh multisig keystore.from_xprv( 'Uprv9CvELvByqm8k2dpecJVjgLMX1z5DufEjY4fBC5YvdGF5WjGCa7GVJJ2fYni1tyuF7Hw83E6W2ZBjAhaFLZv2ri3rEsubkCd5avg4EHKoDBN' ), keystore.from_xpub( 'Upub5Qb8ik4Cnu8g97KLXKgVXHqY6tH8emQvqtBncjSKsyfTZuorPtTZgX7ovKKZHuuVGBVd1MTTBkWez1XXt2weN1sWBz6SfgRPQYEkNgz81QF' ), gap_limit=2) wallet2b = WalletIntegrityHelper.create_multisig_wallet( # bip39: square page wood spy oil story rebel give milk screen slide shuffle, der: m/1234'/1'/0', p2wsh-p2sh multisig keystore.from_xprv( 'Uprv9BbnKEXJxXaNvdEsRJ9VA9toYrSeFJh5UfGBpM2iKe8Uh7UhrM9K8ioL53s8gvCoGfirHHaqpABDAE7VUNw8LNU1DMJKVoWyeNKu9XcDC19' ), keystore.from_xpub( 'Upub5RuakRisg8h3F7u7iL2k3UJFa1uiK7xauHamzTxYBbn4PXbM7eajr6M9Q2VCr6cVGhfhqWQqxnABvtSATuVM1xzxk4nA189jJwzaMn1QX7V' ), gap_limit=2) # bootstrap wallet1 funding_tx = Transaction( '01000000000101a41aae475d026c9255200082c7fad26dc47771275b0afba238dccda98a597bd20000000000fdffffff02400d0300000000002200203c43ac80d6e3015cf378bf6bac0c22456723d6050bef324ec641e7762440c63c9dcd410000000000160014824626055515f3ed1d2cfc9152d2e70685c71e8f02483045022100b9f39fad57d07ce1e18251424034f21f10f20e59931041b5167ae343ce973cf602200fefb727fa0ffd25b353f1bcdae2395898fe407b692c62f5885afbf52fa06f5701210301a28f68511ace43114b674371257bb599fd2c686c4b19544870b1799c954b40e9c11300' ) funding_txid = funding_tx.txid() funding_output_value = 200000 self.assertEqual( 'd2bd6c9d332db8e2c50aa521cd50f963fba214645aab2f7556e061a412103e21', funding_txid) wallet1a.receive_tx_callback(funding_txid, funding_tx, TX_HEIGHT_UNCONFIRMED) # wallet1 -> wallet2 outputs = [(bitcoin.TYPE_ADDRESS, wallet2a.get_receiving_address(), 165000)] tx = wallet1a.mktx(outputs=outputs, password=None, config=self.config, fee=5000) tx = Transaction( tx.serialize()) # simulates moving partial txn between cosigners self.assertFalse(tx.is_complete()) wallet1b.sign_transaction(tx, password=None) self.assertTrue(tx.is_complete()) self.assertTrue(tx.is_segwit()) self.assertEqual(1, len(tx.inputs())) tx_copy = Transaction(tx.serialize()) self.assertEqual(wallet1a.is_mine(tx.inputs()[0]['address']), wallet1a.is_mine(tx_copy.inputs()[0]['address'])) self.assertTrue(wallet1a.is_mine(tx.inputs()[0]['address'])) self.assertEqual(wallet1a.txin_type, tx_copy.inputs()[0]['type']) self.assertEqual(tx.wtxid(), tx_copy.wtxid()) self.assertEqual( '6e9c3cd8788bdb970a124ea06136d52bc01cec4f9b1e217627d5e90ebe77d049', tx_copy.txid()) wallet1a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) wallet2a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) # wallet2 -> wallet1 outputs = [(bitcoin.TYPE_ADDRESS, wallet1a.get_receiving_address(), 100000)] tx = wallet2a.mktx(outputs=outputs, password=None, config=self.config, fee=5000) tx = Transaction( tx.serialize()) # simulates moving partial txn between cosigners self.assertFalse(tx.is_complete()) wallet2b.sign_transaction(tx, password=None) self.assertTrue(tx.is_complete()) self.assertTrue(tx.is_segwit()) self.assertEqual(1, len(tx.inputs())) tx_copy = Transaction(tx.serialize()) self.assertEqual(wallet2a.is_mine(tx.inputs()[0]['address']), wallet2a.is_mine(tx_copy.inputs()[0]['address'])) self.assertTrue(wallet2a.is_mine(tx.inputs()[0]['address'])) self.assertEqual(wallet2a.txin_type, tx_copy.inputs()[0]['type']) self.assertEqual(tx.wtxid(), tx_copy.wtxid()) self.assertEqual( '84b0dcb43022385f7a10e2710e5625a2be3cd6e390387b6100b55500d5eea8f6', tx_copy.txid()) wallet1a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) wallet2a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) # wallet level checks self.assertEqual((0, funding_output_value - 165000 - 5000 + 100000, 0), wallet1a.get_balance()) self.assertEqual((0, 165000 - 5000 - 100000, 0), wallet2a.get_balance())
def test_sending_between_p2sh_2of3_and_uncompressed_p2pkh( self, mock_write): wallet1a = WalletIntegrityHelper.create_multisig_wallet( keystore.from_seed( 'blast uniform dragon fiscal ensure vast young utility dinosaur abandon rookie sure', '', True), keystore.from_xpub( 'tpubD6NzVbkrYhZ4YTPEgwk4zzr8wyo7pXGmbbVUnfYNtx6SgAMF5q3LN3Kch58P9hxGNsTmP7Dn49nnrmpE6upoRb1Xojg12FGLuLHkVpVtS44' ), keystore.from_xpub( 'tpubD6NzVbkrYhZ4XJzYkhsCbDCcZRmDAKSD7bXi9mdCni7acVt45fxbTVZyU6jRGh29ULKTjoapkfFsSJvQHitcVKbQgzgkkYsAmaovcro7Mhf' ), gap_limit=2) wallet1b = WalletIntegrityHelper.create_multisig_wallet( keystore.from_seed( 'cycle rocket west magnet parrot shuffle foot correct salt library feed song', '', True), keystore.from_xpub( 'tpubD6NzVbkrYhZ4YTPEgwk4zzr8wyo7pXGmbbVUnfYNtx6SgAMF5q3LN3Kch58P9hxGNsTmP7Dn49nnrmpE6upoRb1Xojg12FGLuLHkVpVtS44' ), keystore.from_xpub( 'tpubD6NzVbkrYhZ4YARFMEZPckrqJkw59GZD1PXtQnw14ukvWDofR7Z1HMeSCxfYEZVvg4VdZ8zGok5VxHwdrLqew5cMdQntWc5mT7mh1CSgrnX' ), gap_limit=2) # ^ third seed: ghost into match ivory badge robot record tackle radar elbow traffic loud wallet2 = self.create_standard_wallet_from_seed( 'powerful random nobody notice nothing important anyway look away hidden message over' ) # bootstrap wallet1 funding_tx = Transaction( '010000000001014121f99dc02f0364d2dab3d08905ff4c36fc76c55437fd90b769c35cc18618280100000000fdffffff02d4c22d00000000001600143fd1bc5d32245850c8cb5be5b09c73ccbb9a0f75001bb7000000000017a91480c2353f6a7bc3c71e99e062655b19adb3dd2e4887024830450221008781c78df0c9d4b5ea057333195d5d76bc29494d773f14fa80e27d2f288b2c360220762531614799b6f0fb8d539b18cb5232ab4253dd4385435157b28a44ff63810d0121033de77d21926e09efd04047ae2d39dbd3fb9db446e8b7ed53e0f70f9c9478f735dac11300' ) funding_txid = funding_tx.txid() funding_output_value = 12000000 self.assertEqual( 'b25cd55687c9e528c2cfd546054f35fb6741f7cf32d600f07dfecdf2e1d42071', funding_txid) wallet1a.receive_tx_callback(funding_txid, funding_tx, TX_HEIGHT_UNCONFIRMED) # wallet1 -> wallet2 outputs = [(bitcoin.TYPE_ADDRESS, wallet2.get_receiving_address(), 370000)] tx = wallet1a.mktx(outputs=outputs, password=None, config=self.config, fee=5000) tx = Transaction( tx.serialize()) # simulates moving partial txn between cosigners self.assertFalse(tx.is_complete()) wallet1b.sign_transaction(tx, password=None) self.assertTrue(tx.is_complete()) self.assertFalse(tx.is_segwit()) self.assertEqual(1, len(tx.inputs())) tx_copy = Transaction(tx.serialize()) self.assertEqual(wallet1a.is_mine(tx.inputs()[0]['address']), wallet1a.is_mine(tx_copy.inputs()[0]['address'])) self.assertTrue(wallet1a.is_mine(tx.inputs()[0]['address'])) self.assertEqual(wallet1a.txin_type, tx_copy.inputs()[0]['type']) self.assertEqual(tx.wtxid(), tx_copy.wtxid()) self.assertEqual( '26f3bdd0402e1cff19126244ebe3d32722cef0db507c7229ca8754f5e06ef25d', tx_copy.txid()) wallet1a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) wallet2.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) # wallet2 -> wallet1 outputs = [(bitcoin.TYPE_ADDRESS, wallet1a.get_receiving_address(), 100000)] tx = wallet2.mktx(outputs=outputs, password=None, config=self.config, fee=5000) self.assertTrue(tx.is_complete()) self.assertFalse(tx.is_segwit()) self.assertEqual(1, len(tx.inputs())) tx_copy = Transaction(tx.serialize()) self.assertEqual(wallet2.is_mine(tx.inputs()[0]['address']), wallet2.is_mine(tx_copy.inputs()[0]['address'])) self.assertTrue(wallet2.is_mine(tx.inputs()[0]['address'])) self.assertEqual(wallet2.txin_type, tx_copy.inputs()[0]['type']) self.assertEqual(tx.wtxid(), tx_copy.wtxid()) self.assertEqual( 'c573b3f8464a4ed40dfc79d0889a780f44e917beef7a75883b2427c2987f3e95', tx_copy.txid()) wallet1a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) wallet2.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) # wallet level checks self.assertEqual((0, funding_output_value - 370000 - 5000 + 100000, 0), wallet1a.get_balance()) self.assertEqual((0, 370000 - 5000 - 100000, 0), wallet2.get_balance())
def test_sending_between_p2wpkh_and_compressed_p2pkh(self, mock_write): wallet1 = self.create_standard_wallet_from_seed( 'bitter grass shiver impose acquire brush forget axis eager alone wine silver' ) wallet2 = self.create_standard_wallet_from_seed( 'cycle rocket west magnet parrot shuffle foot correct salt library feed song' ) # bootstrap wallet1 funding_tx = Transaction( '01000000014576dacce264c24d81887642b726f5d64aa7825b21b350c7b75a57f337da6845010000006b483045022100a3f8b6155c71a98ad9986edd6161b20d24fad99b6463c23b463856c0ee54826d02200f606017fd987696ebbe5200daedde922eee264325a184d5bbda965ba5160821012102e5c473c051dae31043c335266d0ef89c1daab2f34d885cc7706b267f3269c609ffffffff0240420f00000000001600148a28bddb7f61864bdcf58b2ad13d5aeb3abc3c42a2ddb90e000000001976a914c384950342cb6f8df55175b48586838b03130fad88ac00000000' ) funding_txid = funding_tx.txid() funding_output_value = 1000000 self.assertEqual( 'add2535aedcbb5ba79cc2260868bb9e57f328738ca192937f2c92e0e94c19203', funding_txid) wallet1.receive_tx_callback(funding_txid, funding_tx, TX_HEIGHT_UNCONFIRMED) # wallet1 -> wallet2 outputs = [(bitcoin.TYPE_ADDRESS, wallet2.get_receiving_address(), 250000)] tx = wallet1.mktx(outputs=outputs, password=None, config=self.config, fee=5000) self.assertTrue(tx.is_complete()) self.assertTrue(tx.is_segwit()) self.assertEqual(1, len(tx.inputs())) tx_copy = Transaction(tx.serialize()) self.assertEqual(wallet1.is_mine(tx.inputs()[0]['address']), wallet1.is_mine(tx_copy.inputs()[0]['address'])) self.assertTrue(wallet1.is_mine(tx.inputs()[0]['address'])) self.assertEqual(wallet1.txin_type, tx_copy.inputs()[0]['type']) self.assertEqual(tx.wtxid(), tx_copy.wtxid()) self.assertEqual( '3c06ae4d9be8226a472b3e7f7c127c7e3016f525d658d26106b80b4c7e3228e2', tx_copy.txid()) wallet1.receive_tx_callback( tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) # TX_HEIGHT_UNCONF_PARENT but nvm wallet2.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) # wallet2 -> wallet1 outputs = [(bitcoin.TYPE_ADDRESS, wallet1.get_receiving_address(), 100000)] tx = wallet2.mktx(outputs=outputs, password=None, config=self.config, fee=5000) self.assertTrue(tx.is_complete()) self.assertFalse(tx.is_segwit()) self.assertEqual(1, len(tx.inputs())) tx_copy = Transaction(tx.serialize()) self.assertEqual(wallet2.is_mine(tx.inputs()[0]['address']), wallet2.is_mine(tx_copy.inputs()[0]['address'])) self.assertTrue(wallet2.is_mine(tx.inputs()[0]['address'])) self.assertEqual(wallet2.txin_type, tx_copy.inputs()[0]['type']) self.assertEqual(tx.wtxid(), tx_copy.wtxid()) self.assertEqual( '5f25707571eb776bdf14142f9966bf2a681906e0a79501edbb99a972c2ceb972', tx_copy.txid()) wallet1.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) wallet2.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) # wallet level checks self.assertEqual((0, funding_output_value - 250000 - 5000 + 100000, 0), wallet1.get_balance()) self.assertEqual((0, 250000 - 5000 - 100000, 0), wallet2.get_balance())
def test_transaction(self): wallet_keys = { 'xpub6GDQf5vZmrpQvD4ixNdqHmgSZ76Uo2Cg5isBupnvZpnNbhdRhgdhq9hkfCSKRE31rGfYuXNfZ5gTamFkj1GXt6k87MD1hUn28tuvLHY71Bk': 'L2FQCaHPwgS4CmAf6bKtbjVWDbcHv42c72by1zLEyLuDrUG22CwM', 'xpub6GLs33TeHkrLSTJ2uxiMLnuqxCHG9iBFCwjTwyg4EvzyxUi78U1sXxxRPUQfLGNEZRT3yYKEwR39ZbUtofEgcmTLtJdSetnFiQPEwTZRW5y': 'L1aD1WSA3UGU56sAmjfYVj1rK3fnSzWKj2wTsDTN1DpgUgPVwQCa', 'xpub6Fc64k9RTc79yD7xErF2yKSdUraGBhGWDt1FomUFVCFg52165LZvvoGL59hebJBGtauFqNL5zMeRgPGV29sfQp6XqoiiD9E53UDatBhFZuk': 'L25eCRYrDNVNrTZV1XZhmaZti3dVsZz3egm1R7LsPHRdpYuyLYKE' # 'xpub6GiSmJrVQC5q2m5cRcZvUgnGUsfeEqi3eEfUTgacnA33G8PAQnJeeMzpNAGUA9JL3goUui7BY52rVPwhmxMALkmFh5ZuwJDKrPv8ERkG3CK': 'L3jUPoR7fUwB9mwfuqqF79mHDpj5rpygQhdWntJ9ShZ9nbyRab5h' } acc = self.wallet.accounts["0"] redeem_script = '53210278a1a7de63493a8c8e0e7f4ebb13fd2a8144db25bb3bc2e5f44127a851a389332102ee780aa224c9fe54caff984205077b7cca08ced3188a3f3c639d83deda6b9a592103124429ddbed55593d0abea0d0d3d283eca4546e40017b2945f4666c561b494ba210312872f0aa80fa1a9bc7df77fa5be310f5441f7bfec798fe19209b04954dec8da54ae' coins = [{ 'address': '32SbQbBthcMzRSpCw1ifAXqWviJGH5HKUk', 'value': 600000, 'prevout_n': 0, 'prevout_hash': '1111111111111111111111111111111111111111111111111111111111111111', 'height': 100000, 'coinbase': 'True' }] txin = coins[0] x_pubkeys = map(lambda x: bip32_public_derivation(x, "", "/0/0/0"), self.wallet.master_public_keys.values()) pubkeys = map(lambda x: deserialize_xkey(x)[4].encode('hex'), x_pubkeys) s = ''.join(map(lambda x: int_to_hex(x, 2), (0, 0))) x_pubkeys = map( lambda x: 'ff' + DecodeBase58Check(x).encode('hex') + s, x_pubkeys) pubkeys, x_pubkeys = zip(*sorted(zip(pubkeys, x_pubkeys))) txin['pubkeys'] = list(pubkeys) txin['x_pubkeys'] = list(x_pubkeys) txin['signatures'] = [None] * len(pubkeys) txin['redeemScript'] = redeem_script txin['num_sig'] = acc.multisig_m outputs = [('address', '1PyXgL1qmZPuxcVi9CcguQb3v7WUvQZBud', 500000)] inputs = [] tx = Transaction(inputs, outputs) tx.add_input(txin) self.wallet.sign_transaction(tx, "secret") # ins = tx.inputs_to_sign() keypairs = {} sec = None for innard in ins: # this is easier than the commented loop below in_xpub, _ = BIP32_Account.parse_xpubkey(innard) if wallet_keys.get(in_xpub): keypairs[innard] = wallet_keys[in_xpub] # ... # in_xpub, in_seq = BIP32_Account.parse_xpubkey(innard) # sec = None # for k, vaccount in self.wallet.accounts.items(): # acc_v = vaccount.get_master_pubkeys()[0] # acc_xpub = bip32_public_derivation(acc_v, "", "/0/0") # if in_xpub == acc_xpub: # pk = vaccount.get_private_key(in_seq, self.wallet, "secret") # sec = pk[0] # if sec: # keypairs [ innard ] = sec if keypairs: tx.sign(keypairs) self.assertEqual( '0100000001111111111111111111111111111111111111111111111111111111111111111100000000fd6701004730440220774e80fda89895d8bf3ac39c38f39456d31c1e857dc1c77c000f4de6c3de15fe02207b6d13b5ba17eadeb607f3ca56f693a0b777dae668584cefec0910a8bc90869a0147304402205e80562254972f873b5b59b1cdc81e422c7a2959d8868e5a54238fbfdf6f107002200204eef593812453ae2c22334c409f9ef25523cf9619399eb2d3c249673443dc01483045022100a81e69796aa5e5ae0d8924047e3c81a8dd64dfbc791caba6728ac7820aa114da022060b85875fd58223b7c61ef45fac2567a9f76934f947e4d03d927f5b078e1fb45014c8b53210278a1a7de63493a8c8e0e7f4ebb13fd2a8144db25bb3bc2e5f44127a851a389332102ee780aa224c9fe54caff984205077b7cca08ced3188a3f3c639d83deda6b9a592103124429ddbed55593d0abea0d0d3d283eca4546e40017b2945f4666c561b494ba210312872f0aa80fa1a9bc7df77fa5be310f5441f7bfec798fe19209b04954dec8da54aeffffffff0120a10700000000001976a914fc03ab7c28d17349f084f7cadde4dafc356918d388ac00000000', str(tx)) ########### # serialized_tx = str(tx) tx2 = Transaction.deserialize(serialized_tx, active_chain=self.wallet.active_chain) self.assertEquals(4, len(tx2.inputs[0]['x_pubkeys'])) self.assertEquals(3, tx2.inputs[0]['num_sig'])
def test_coinstake_marker(self): raw_tx = '02000000704d4a55010000000000000000000000000000000000000000000000000000000000000000ffffffff04033df406ffffffff010000000000000000000000000000' tx = Transaction(raw_tx) tx.deserialize() self.assertEquals(tx.inputs[0]['is_coinbase'], True)
def test_coinstake(self): tx = Transaction(self.coinstake_tx) tx.deserialize() self.assertEquals(tx.is_coinstake, True)
def test_peercoin_serialize(self): chainparams.set_active_chain('PPC') rawtx = '0100000058e4615501a367e883a383167e64c84e9c068ba5c091672e434784982f877eede589cb7e53000000006a473044022043b9aee9187effd7e6c7bc444b09162570f17e36b4a9c02cf722126cc0efa3d502200b3ba14c809fa9a6f7f835cbdbbb70f2f43f6b30beaf91eec6b8b5981c80cea50121025edf500f18f9f2b3f175f823fa996fbb2ec52982a9aeb1dc2e388a651054fb0fffffffff0257be0100000000001976a91495efca2c6a6f0e0f0ce9530219b48607a962e77788ac45702000000000001976a914f28abfb465126d6772dcb4403b9e1ad2ea28a03488ac00000000' tx = Transaction.deserialize(rawtx, chainparams.get_active_chain()) self.assertEqual(tx.serialize()[8:16], rawtx[8:16])
def test_serialize(self): chainparams.set_active_chain('BTC') rawtx = '010000000198fb6f1c46eb0416b6a91bc9d0b8dfa554a96b23f00070f430bbf6d05b26ea16010000006c493046022100d00ff7bb2e9d41ef200ceb2fd874468b09a21e549ead6f2a74f35ad02ce25df8022100b1307da37c806ae638502c60d0ebbbe6da2ae9bb03f8798953059269e0ef3b46012102e7d08484e6c4c26bd2a3aabab09c65bbdcb4a6bba0ee5cf7008ef19b9540f818ffffffff0200743ba40b0000001976a91429a158767437cd82ccf4bd3e34ecd16c267fc36388aca0c01319180000001976a9140b31340661bb7a4165736ca2fc6509164b1dc96488ac00000000' tx = Transaction.deserialize(rawtx, chainparams.get_active_chain()) self.assertEqual(str(tx), rawtx)
def test_transaction(self): wallet_keys = { 'xpub6GDQf5vZmrpQvD4ixNdqHmgSZ76Uo2Cg5isBupnvZpnNbhdRhgdhq9hkfCSKRE31rGfYuXNfZ5gTamFkj1GXt6k87MD1hUn28tuvLHY71Bk': 'L2FQCaHPwgS4CmAf6bKtbjVWDbcHv42c72by1zLEyLuDrUG22CwM', 'xpub6GLs33TeHkrLSTJ2uxiMLnuqxCHG9iBFCwjTwyg4EvzyxUi78U1sXxxRPUQfLGNEZRT3yYKEwR39ZbUtofEgcmTLtJdSetnFiQPEwTZRW5y': 'L1aD1WSA3UGU56sAmjfYVj1rK3fnSzWKj2wTsDTN1DpgUgPVwQCa', 'xpub6Fc64k9RTc79yD7xErF2yKSdUraGBhGWDt1FomUFVCFg52165LZvvoGL59hebJBGtauFqNL5zMeRgPGV29sfQp6XqoiiD9E53UDatBhFZuk': 'L25eCRYrDNVNrTZV1XZhmaZti3dVsZz3egm1R7LsPHRdpYuyLYKE' # 'xpub6GiSmJrVQC5q2m5cRcZvUgnGUsfeEqi3eEfUTgacnA33G8PAQnJeeMzpNAGUA9JL3goUui7BY52rVPwhmxMALkmFh5ZuwJDKrPv8ERkG3CK': 'L3jUPoR7fUwB9mwfuqqF79mHDpj5rpygQhdWntJ9ShZ9nbyRab5h' } acc = self.wallet.accounts["0"] redeem_script = '53210278a1a7de63493a8c8e0e7f4ebb13fd2a8144db25bb3bc2e5f44127a851a389332102ee780aa224c9fe54caff984205077b7cca08ced3188a3f3c639d83deda6b9a592103124429ddbed55593d0abea0d0d3d283eca4546e40017b2945f4666c561b494ba210312872f0aa80fa1a9bc7df77fa5be310f5441f7bfec798fe19209b04954dec8da54ae' coins = [ {'address': '32SbQbBthcMzRSpCw1ifAXqWviJGH5HKUk', 'value': 600000, 'prevout_n': 0, 'prevout_hash': '1111111111111111111111111111111111111111111111111111111111111111', 'height': 100000, 'coinbase': 'True' } ] txin = coins[0] x_pubkeys = map( lambda x:bip32_public_derivation(x, "", "/0/0/0"), self.wallet.master_public_keys.values() ) pubkeys = map(lambda x: deserialize_xkey(x)[4].encode('hex'), x_pubkeys) s = ''.join( map(lambda x: int_to_hex(x, 2), (0, 0))) x_pubkeys = map( lambda x: 'ff' + DecodeBase58Check(x).encode('hex') + s, x_pubkeys) pubkeys, x_pubkeys = zip( *sorted(zip(pubkeys, x_pubkeys))) txin['pubkeys'] = list(pubkeys) txin['x_pubkeys'] = list(x_pubkeys) txin['signatures'] = [None] * len(pubkeys) txin['redeemScript'] = redeem_script txin['num_sig'] = acc.multisig_m outputs = [ ('address', '1PyXgL1qmZPuxcVi9CcguQb3v7WUvQZBud', 500000) ] inputs = [] tx = Transaction(inputs, outputs) tx.add_input(txin) self.wallet.sign_transaction(tx, "secret") # ins = tx.inputs_to_sign() keypairs = {} sec = None for innard in ins: # this is easier than the commented loop below in_xpub, _ = BIP32_Account.parse_xpubkey(innard) if wallet_keys.get(in_xpub): keypairs[ innard ] = wallet_keys[in_xpub] # ... # in_xpub, in_seq = BIP32_Account.parse_xpubkey(innard) # sec = None # for k, vaccount in self.wallet.accounts.items(): # acc_v = vaccount.get_master_pubkeys()[0] # acc_xpub = bip32_public_derivation(acc_v, "", "/0/0") # if in_xpub == acc_xpub: # pk = vaccount.get_private_key(in_seq, self.wallet, "secret") # sec = pk[0] # if sec: # keypairs [ innard ] = sec if keypairs: tx.sign(keypairs) self.assertEqual('0100000001111111111111111111111111111111111111111111111111111111111111111100000000fd6701004730440220774e80fda89895d8bf3ac39c38f39456d31c1e857dc1c77c000f4de6c3de15fe02207b6d13b5ba17eadeb607f3ca56f693a0b777dae668584cefec0910a8bc90869a0147304402205e80562254972f873b5b59b1cdc81e422c7a2959d8868e5a54238fbfdf6f107002200204eef593812453ae2c22334c409f9ef25523cf9619399eb2d3c249673443dc01483045022100a81e69796aa5e5ae0d8924047e3c81a8dd64dfbc791caba6728ac7820aa114da022060b85875fd58223b7c61ef45fac2567a9f76934f947e4d03d927f5b078e1fb45014c8b53210278a1a7de63493a8c8e0e7f4ebb13fd2a8144db25bb3bc2e5f44127a851a389332102ee780aa224c9fe54caff984205077b7cca08ced3188a3f3c639d83deda6b9a592103124429ddbed55593d0abea0d0d3d283eca4546e40017b2945f4666c561b494ba210312872f0aa80fa1a9bc7df77fa5be310f5441f7bfec798fe19209b04954dec8da54aeffffffff0120a10700000000001976a914fc03ab7c28d17349f084f7cadde4dafc356918d388ac00000000', str(tx)) ########### # serialized_tx = str(tx) tx2 = Transaction.deserialize(serialized_tx, active_chain = self.wallet.active_chain) self.assertEquals(4, len( tx2.inputs[0]['x_pubkeys']) ) self.assertEquals(3, tx2.inputs[0]['num_sig'] )