def test_serialization(): outpoint1 = OutPoint(txid='coffee', txout_idx=0) outpoint2 = OutPoint(txid='coffee', txout_idx=0) txin1 = TxIn(outpoint=outpoint1, signature=SignatureScript(unlock_sig=b'sign', unlock_pk=b'bar'), sequence=1) txin2 = TxIn(outpoint=outpoint2, signature=SignatureScript(unlock_sig=b'sign', unlock_pk=b'bar'), sequence=2) txout = TxOut(value=101, pubkey='abcnddfjrwof123') txn1 = Transaction(txins=[txin1], txouts=[txout], locktime=0) txn2 = Transaction(txins=[txin2], txouts=[txout], locktime=0) block = Block(1, 'deadbeef', 'coffee', int(time.time()), 100, 100, [txn1, txn2]) utxo = UnspentTxOut(*txout, txid=txn1.id, txout_idx=0, is_coinbase=False, height=0) utxo_set = [utxo.outpoint, utxo] for obj in (outpoint1, outpoint2, txin1, txin2, txout, txn1, txn2, block, utxo, utxo_set): assert deserialize(serialize(obj)) == obj
def pool_solver(rng): print(f"calculating range {rng}") for nonce in rng: b = Block( version=0, prev_block_hash= '000000273d64c0b32fa8475004513d1e5f8335a718dc9bd6c99f60d5cf6f7175', merkle_tree_hash= '5b9f0cb4023a18cd1de03c0035283965aa6b14ec72a5d9ce7b2a029a9afce47a', timestamp=1501827000, bits=24, nonce=nonce, txns=[ Transaction( txins=[ TxIn(outpoint=None, signature=SignatureScript(unlock_sig=b'4', unlock_pk=None), sequence=0) ], txouts=[ TxOut(value=5000000000, pubkey='1Piq91dFUqSb7tdddCWvuGX5UgdzXeoAwA') ], locktime=None) ]) if int(b.id, 16) <= (1 << (256 - b.bits)): return nonce, b.id return None
def assemble_and_solve_block(pay_coinbase_to_addr, txns=None): """ Construct a Block by pulling transactions from the mempool, the mine it """ with chain_lock: prev_block_hash = get_active_chain()[-1].id if get_active_chain( ) else None block = Block(version=0, prev_block_hash=prev_block_hash, merkle_tree_hash='', timestamp=int(time.time()), bits=get_next_work_required(prev_block_hash), nonce=0, txns=txns or []) if not block.txns: block = select_from_mempool(block) fees = calculate_fees(block) coinbase_txn = Transaction.create_coinbase(pay_coinbase_to_addr, (get_block_subsidy() + fees), len(get_active_chain())) block = block._replace(txns=[coinbase_txn, *block.txns]) block = block._replace( merkle_tree_hash=get_merkle_root_of_txns(block.txns).value) if len(serialize(block)) > Params.MAX_BLOCK_SERIALIZED_SIZE: raise ValueError('txns specified create a block too large') return mine(block)
def test_dependent_txns_in_single_block(): set_active_chain([]) mempool.clear() assert connect_block(chain1[0]) == ACTIVE_CHAIN_IDX assert connect_block(chain1[1]) == ACTIVE_CHAIN_IDX assert len(get_active_chain()) == 2 assert len(utxo_set) == 2 utxo1 = utxo_set[list(utxo_set.keys())[0]] txout1 = TxOut(value=901, pubkey=utxo1.pubkey) txin1 = make_txin(signing_key, utxo1.outpoint, txout1) txn1 = Transaction(txins=[txin1], txouts=[txout1], locktime=0) # Create a transaction that is depend on the yet-unconfirmed transaction above txout2 = TxOut(value=9001, pubkey=txout1.pubkey) txin2 = make_txin(signing_key, OutPoint(txn1.id, 0), txout2) txn2 = Transaction(txins=[txin2], txouts=[txout2], locktime=0) # assert that we don't accept this txn -- too early to spend the coinbase with pytest.raises(TxnValidationError) as excinfo: validate_txn(txn2) assert 'Spend value is more than available' in str(excinfo) connect_block(chain1[2]) add_txn_to_mempool(txn1) assert txn1.id in mempool # In txn2, we're attemping to spend more than is available (9001 vs. 901). assert not add_txn_to_mempool(txn2) with pytest.raises(TxnValidationError) as excinfo: validate_txn(txn2) assert 'Spend value is more than available' in str(excinfo.value) # Recreate the transaction with an acceptable value txout2 = TxOut(value=901, pubkey=txout1.pubkey) txin2 = make_txin(signing_key, OutPoint(txn1.id, 0), txout2) txn2 = Transaction(txins=[txin2], txouts=[txout2], locktime=0) add_txn_to_mempool(txn2) assert txn2.id in mempool
def validate_txn(txn: Transaction, as_coinbase: bool = False, siblings_in_block: Iterable[Transaction] = None, allow_utxo_from_mempool: bool = True): """ Validate a single transaction. Used in various contexts, so the parameters facilitate difficult users """ txn.validate_basics(as_coinbase=as_coinbase) available_to_spend = 0 for i, txin in enumerate(txn.txins): utxo = utxo_set.get(txin.outpoint) if siblings_in_block: utxo = utxo or find_utxo_in_list(txin, siblings_in_block) if allow_utxo_from_mempool: utxo = utxo or find_utxo_in_mempool(txin) if not utxo: raise TxnValidationError( f'Could not find UTXO for TxIn[{i}] -- orphaning txn', to_orphan=txn) if utxo.is_coinbase and (get_current_height() - utxo.height) < Params.COINBASE_MATURITY: raise TxnValidationError(f'Coinbase UTXO not ready for spend') try: validate_signature_for_spend(txin, utxo, txn) except TxUnlockError: raise TxnValidationError(f'{txin} is not valid spend of {utxo}') available_to_spend += utxo.value if available_to_spend < sum(o.value for o in txn.txouts): raise TxnValidationError('Spend value is more than available') return txn
def test_build_spend_message(): txout = TxOut(value=101, pubkey='1zz8w9') txin = TxIn(outpoint=OutPoint('c0ffee', 0), signature=SignatureScript(unlock_sig=b'oursig', unlock_pk=b'foo'), sequence=1) txn = Transaction(txins=[txin], txouts=[txout], locktime=0) spend_msg = build_spend_message(txin.outpoint, txin.signature.unlock_pk, txin.sequence, txn.txouts) assert spend_msg == b'2c162f2c05a771e52c01fda220073aa0665cc873193235bdb90359631720e7a5' # adding a new output to the txn creates a new spend message. txn.txouts.append(TxOut(value=1, pubkey='1zz')) assert build_spend_message(txin.outpoint, txin.signature.unlock_pk, txin.sequence, txn.txouts) != spend_msg
def send_value(args): """ Send value to some address. """ val, to_addr, sk = int(args['<val>']), args['<addr>'], args['signing_key'] selected = set() my_utxos = set( sorted(find_utxos_for_address(args), key=lambda i: (i.value, i.height))) for utxo in my_utxos: selected.add(utxo) if sum(i.value for i in selected) > val: break txout = TxOut(value=val, pubkey=to_addr) txn = Transaction( txins=[make_txin(sk, coin.outpoint, txout) for coin in selected], txouts=[txout]) logger.info(f'built txn {txn}') logger.info(f'broadcast txn {txn.id}') send_msg(txn)
# Block id: # 0000009284177ad434618ded91f9f81fad78e0c26f77cffb5d9a406a8d4dab80 Block(version=0, prev_block_hash=None, merkle_tree_hash= '548b61957ff5fb0cb3d2c511f1a6e28460f0d7175eaa3058bfac986d37a72004', timestamp=1501821412, bits=24, nonce=2275359062, txns=[ Transaction(txins=[ TxIn(outpoint=None, signature=SignatureScript(unlock_sig=b'0', unlock_pk=None), sequence=0) ], txouts=[ TxOut( value=5000000000, pubkey='143UVyz7ooiAv1pMqbwPPpnH4BV9ifJGFF') ], locktime=None) ]), # Block id: # 000000d432bd0ec0a087a0d30a6e5c251116919bf91e195f1f9c3d4f3e3f0ba3 Block(version=0, prev_block_hash= '0000009284177ad434618ded91f9f81fad78e0c26f77cffb5d9a406a8d4dab80', merkle_tree_hash= '509dd8d49774ddf72c24f83faa5a2e851da514103f53e6bec3df4ad5f83d8421', timestamp=1501826444,
'prev_block_hash': None, 'merkle_tree_hash': '688787d8ff144c502c7f5cffaafe2cc588d86079f9de88304c26b0cb99ce91c6', 'timestamp': 1504563279, 'bits': 24, 'nonce': 86038336, 'txns': [ Transaction(txins=[ TxIn(outpoint=None, signature=SignatureScript(unlock_sig=b'0', unlock_pk=None), sequence=0) ], txouts=[ TxOut(value=5000000, pubkey='143UVyz7ooiAv1pMqbwPPpnH4BV9ifJGFF') ]) ] }) # highest proof of work active_chain: Iterable[Block] = [genesis_block] # side branches side_branches: Iterable[Iterable[Block]] = [] orphan_blocks: Iterable[Block] = []