def spend_input(state, utxo_cache: UTXOCache, address, seq_no, is_committed=False, remove_spent=True): state_key = TokenStaticHelper.create_state_key(address, seq_no) if remove_spent: state.remove(state_key) else: state.set(state_key, b'') utxo_cache.spend_output(Output(address, seq_no, None), is_committed=is_committed)
def update_state(self, txn, prev_result, request, is_committed=False): try: payload = get_payload_data(txn) seq_no = get_seq_no(txn) for output in payload[OUTPUTS]: TokenStaticHelper.add_new_output( self.state, self.database_manager.get_store(UTXO_CACHE_LABEL), Output(output["address"], seq_no, output["amount"]), is_committed=is_committed) except UTXOError as ex: error = 'Exception {} while updating state'.format(ex) raise OperationError(error)
def test_token_req_handler_commit_success(helpers, addresses, token_handler_b, txnPoolNodeSet): [address1, address2] = addresses inputs = [{"address": address1, "seqNo": 1}] outputs = [{ "address": address1, "amount": 30 }, { "address": address2, "amount": 30 }] request = helpers.request.transfer(inputs, outputs) # apply transaction state_root = txnPoolNodeSet[1].master_replica.stateRootHash( TOKEN_LEDGER_ID) txn_root = txnPoolNodeSet[1].master_replica.txnRootHash(TOKEN_LEDGER_ID) token_handler_b.apply(request, CONS_TIME) new_state_root = txnPoolNodeSet[1].master_replica.stateRootHash( TOKEN_LEDGER_ID) new_txn_root = txnPoolNodeSet[1].master_replica.txnRootHash( TOKEN_LEDGER_ID) # add batch token_handler_b.onBatchCreated(base58.b58decode(new_state_root.encode())) # commit batch assert token_handler_b.utxo_cache.get_unspent_outputs( address1, True) == [Output(address1, 1, 40)] assert token_handler_b.utxo_cache.get_unspent_outputs( address2, True) == [Output(address2, 1, 60)] commit_ret_val = token_handler_b.commit(1, new_state_root, new_txn_root, None) assert token_handler_b.utxo_cache.get_unspent_outputs( address1, True) == [Output(address1, 2, 30)] assert token_handler_b.utxo_cache.get_unspent_outputs( address2, True) == [Output(address2, 1, 60), Output(address2, 2, 30)] assert new_state_root != state_root assert new_txn_root != txn_root
def test_token_req_handler_sum_inputs_success(helpers, token_handler_a): address = helpers.wallet.create_address() # Verify no outputs pre_add_outputs = token_handler_a.utxo_cache.get_unspent_outputs(address) assert pre_add_outputs == [] # add and verify new unspent output added token_handler_a.utxo_cache.add_output(Output(address, 5, 150)) post_add_outputs = token_handler_a.utxo_cache.get_unspent_outputs(address) assert post_add_outputs == [Output(address, 5, 150)] # add second unspent output and verify token_handler_a.utxo_cache.add_output(Output(address, 6, 100)) post_second_add_outputs = token_handler_a.utxo_cache.get_unspent_outputs(address) assert post_second_add_outputs == [Output(address, 5, 150), Output(address, 6, 100)] # Verify sum_inputs is working properly inputs = [{"address": address, "seqNo": 5}, {"address": address, "seqNo": 6}] outputs = [] request = helpers.request.transfer(inputs, outputs) sum_inputs = token_handler_a._sum_inputs(request) assert sum_inputs == 250
def test_token_req_handler_get_query_response_success(helpers, addresses, token_handler_a): address1 = addresses[0] request = helpers.request.get_utxo(address1) results = token_handler_a.get_query_response(request) state_proof = results.pop(STATE_PROOF) assert state_proof assert results == { ADDRESS: address1, TXN_TYPE: GET_UTXO, OUTPUTS: [Output(address=address1, seq_no=1, value=40)], IDENTIFIER: VALID_IDENTIFIER, TXN_PAYLOAD_METADATA_REQ_ID: request.reqId }
def update_token_state(self, txn, request, is_committed=False): for utxo in txn[TXN_PAYLOAD][TXN_PAYLOAD_DATA][INPUTS]: TokenStaticHelper.spend_input(state=self.token_state, utxo_cache=self.utxo_cache, address=utxo[ADDRESS], seq_no=utxo[SEQNO], is_committed=is_committed) seq_no = get_seq_no(txn) for output in txn[TXN_PAYLOAD][TXN_PAYLOAD_DATA][OUTPUTS]: TokenStaticHelper.add_new_output(state=self.token_state, utxo_cache=self.utxo_cache, output=Output( output[ADDRESS], seq_no, output[AMOUNT]), is_committed=is_committed)
def as_output_list(self) -> List[Output]: if len(self.data) % 2 != 0: raise UTXOError('Length of seqNo-amount pairs must be even: items={}'.format(len(self.data))) rtn = [] for i in range(0, len(self.data), 2): try: seq_no = int(self.data[i]) amount = int(self.data[i + 1]) except ValueError: raise UTXOError("Invalid data -- not integers -- seq_no:{} amount:{}".format(self.data[i], self.data[i + 1])) rtn.append(Output(self.address, seq_no, amount)) return rtn
def test_token_req_handler_onBatchCreated_success(addresses, token_handler_a, txnPoolNodeSet): address = addresses[0] output = Output(address, 10, 100) # add output to UTXO Cache token_handler_a.utxo_cache.add_output(output) state_root = txnPoolNodeSet[1].master_replica.stateRootHash( TOKEN_LEDGER_ID) # run onBatchCreated token_handler_a.onBatchCreated(state_root, CONS_TIME) # Verify onBatchCreated worked properly key = token_handler_a.utxo_cache._create_key(output) assert token_handler_a.utxo_cache.un_committed[0][0] == state_root assert key in token_handler_a.utxo_cache.un_committed[0][1] assert '{}:{}'.format(str(output.seqNo), str( output.amount)) in token_handler_a.utxo_cache.un_committed[0][1][key]
def test_token_req_handler_get_result_success(helpers, addresses, get_utxo_handler): address1 = addresses[0] request = helpers.request.get_utxo(address1) results = get_utxo_handler.get_result(request) state_proof = results.pop(STATE_PROOF) address1 = libsovtoken_address_to_address(address1) assert state_proof assert results == { ADDRESS: address1, TXN_TYPE: GET_UTXO, OUTPUTS: [Output(address=address1, seq_no=1, value=40)], IDENTIFIER: base58.b58encode(base58.b58decode_check(address1)).decode(), TXN_PAYLOAD_METADATA_REQ_ID: request.reqId }
def test_token_req_handler_get_query_response_success( helpers, addresses, token_handler_a ): address1 = addresses[0] request = helpers.request.get_utxo(address1) results = token_handler_a.get_query_response(request) state_proof = results.pop(STATE_PROOF) address1 = address1.replace("pay:sov:", "") assert state_proof assert results == { ADDRESS: address1, TXN_TYPE: GET_UTXO, OUTPUTS: [Output(address=address1, seq_no=1, value=40)], IDENTIFIER: base58.b58encode(base58.b58decode_check(address1)).decode(), TXN_PAYLOAD_METADATA_REQ_ID: request.reqId }
def update_state(self, txn, prev_result, request, is_committed=False): try: payload = get_payload_data(txn) for inp in payload[INPUTS]: TokenStaticHelper.spend_input(self.state, self.utxo_cache, inp["address"], inp["seqNo"], is_committed=is_committed) for output in payload[OUTPUTS]: seq_no = get_seq_no(txn) TokenStaticHelper.add_new_output(self.state, self.utxo_cache, Output( output["address"], seq_no, output["amount"]), is_committed=is_committed) except UTXOError as ex: error = 'Exception {} while updating state'.format(ex) raise OperationError(error)
def test_token_req_handler_updateState_XFER_PUBLIC_success( helpers, addresses, token_handler_a): [address1, address2] = addresses seq_no = 1 inputs = [{"address": address1, "seqNo": seq_no}] outputs = [{"address": address2, "amount": 40}] request = helpers.request.transfer(inputs, outputs) txn = reqToTxn(request) append_txn_metadata(txn, seq_no=seq_no) token_handler_a.validate(request) token_handler_a.updateState([txn]) state_key = TokenReqHandler.create_state_key(address1, seq_no) key = token_handler_a.utxo_cache._create_key(Output(address1, seq_no, 60)) assert token_handler_a.utxo_cache._store._has_key(key) try: token_handler_a.state.get(state_key, False) except Exception: pytest.fail("This state key isn't in the state")
def get_all_utxo(self, request: Request): address = request.operation[ADDRESS] encoded_root_hash = state_roots_serializer.serialize( bytes(self.state.committedHeadHash)) proof, rv = self.state.generate_state_proof_for_keys_with_prefix( address, serialize=True, get_value=True) multi_sig = self.bls_store.get(encoded_root_hash) if multi_sig: encoded_proof = proof_nodes_serializer.serialize(proof) proof = { MULTI_SIGNATURE: multi_sig.as_dict(), ROOT_HASH: encoded_root_hash, PROOF_NODES: encoded_proof } else: proof = {} # The outputs need to be returned in sorted order since each node's reply should be same. # Since no of outputs can be large, a concious choice to not use `operator.attrgetter` on an # already constructed list was made outputs = SortedItems() for k, v in rv.items(): addr, seq_no = self.parse_state_key(k.decode()) amount = rlp_decode(v)[0] if not amount: continue outputs.add(Output(addr, int(seq_no), int(amount))) result = { f.IDENTIFIER.nm: request.identifier, f.REQ_ID.nm: request.reqId, OUTPUTS: outputs.sorted_list } if proof: result[STATE_PROOF] = proof result.update(request.operation) return result
def test_token_req_handler_update_state_XFER_PUBLIC_success( helpers, addresses, xfer_handler_a): [address1, address2] = addresses seq_no = 1 inputs = [{"source": utxo_from_addr_and_seq_no(address1, seq_no)}] outputs = [{"address": address2, "amount": 40}] request = helpers.request.transfer(inputs, outputs) txn = reqToTxn(request) append_txn_metadata(txn, seq_no=seq_no) xfer_handler_a.dynamic_validation(request) xfer_handler_a.update_state(txn, None, request) state_key = TokenStaticHelper.create_state_key( libsovtoken_address_to_address(address1), seq_no) utxo_cache = xfer_handler_a.database_manager.get_store(UTXO_CACHE_LABEL) key = utxo_cache._create_key( Output(libsovtoken_address_to_address(address1), seq_no, 60)) assert utxo_cache._store._has_key(key) try: xfer_handler_a.state.get(state_key, False) except Exception: pytest.fail("This state key isn't in the state")
def spend_input(state, utxo_cache, address, seq_no, is_committed=False): state_key = TokenReqHandler.create_state_key(address, seq_no) state.set(state_key, b'') utxo_cache.spend_output(Output(address, seq_no, None), is_committed=is_committed)
def gen_outputs(num): return [ Output(randomString(32), random.randint(1000, 10000), random.randint(100, 500)) for i in range(num) ]
def test_create_key(utxo_cache): output = Output(VALID_ADDR_1, 10, 10) key = utxo_cache._create_key(output) assert key == '6baBEYA94sAphWBA5efEsaA6X2wCdyaH7PXuBtv2H5S1'
def test_spend_output_fail_output_not_in_cache(utxo_cache): output = Output(VALID_ADDR_1, 10, 10) with pytest.raises(UTXOError): utxo_cache.spend_output(output)
def test_token_req_handler_add_new_output_success(helpers, token_handler_a): address = helpers.wallet.create_address() token_handler_a._add_new_output(Output(address, 8, 350)) unspent_outputs = token_handler_a.utxo_cache.get_unspent_outputs(address) assert unspent_outputs == [Output(address, 8, 350)]
def test_token_req_handler_onBatchRejected_success(addresses, token_handler_a): address1 = addresses[0] token_handler_a._add_new_output(Output(address1, 40, 100)) token_handler_a.onBatchRejected() assert token_handler_a.utxo_cache.un_committed == []
def test_outputs_in_order(): o1 = Output('a', 1, 8) o2 = Output('a', 2, 9) o3 = Output('a', 9, 10) o4 = Output('a', 22, 11) o5 = Output('b', 3, 3) o6 = Output('b', 6, 6) o7 = Output('b', 4, 7) sr = SortedItems() sr.add(o6) sr.add(o5) sr.add(o2) sr.add(o7) sr.add(o1) sr.add(o4) sr.add(o3) assert sr.sorted_list == [Output(address='a', seq_no=1, value=8), Output(address='a', seq_no=2, value=9), Output(address='b', seq_no=3, value=3), Output(address='b', seq_no=4, value=7), Output(address='b', seq_no=6, value=6), Output(address='a', seq_no=9, value=10), Output(address='a', seq_no=22, value=11)] outputs = [Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=312, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=313, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=314, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=315, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=316, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=319, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=317, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=321, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=318, value=1)] si = SortedItems() for o in outputs: si.add(o) assert si.sorted_list == [Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=312, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=313, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=314, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=315, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=316, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=317, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=318, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=319, value=1), Output(address='2w3WMmR92ijMH3ZV9qNoAUh1i7HjCyqVbBt7e771DdwEWL1K2W', seq_no=321, value=1)]