def test_compute_root_multiple_hashes(self): expected_hash = Helper.bin_dbl_sha256( binascii.unhexlify(b'aa' * 32 + b'bb' * 32)) hash1 = UInt256(data=binascii.unhexlify(b'aa' * 32)) hash2 = UInt256(data=binascii.unhexlify(b'bb' * 32)) hashes = [hash1, hash2] root = MerkleTree.ComputeRoot(hashes) self.assertEqual(expected_hash, root.ToArray())
def test_trim_tree(self): hash1 = UInt256(data=binascii.unhexlify(b'aa' * 32)) hash2 = UInt256(data=binascii.unhexlify(b'bb' * 32)) hash3 = UInt256(data=binascii.unhexlify(b'cc' * 32)) hashes = [hash1, hash2, hash3] m = MerkleTree(hashes) flags = bytearray.fromhex('0000') m.Trim(flags) self.assertEqual(None, m.Root.LeftChild) self.assertEqual(None, m.Root.RightChild)
def test_trim_node3(self): hash1 = UInt256(data=binascii.unhexlify(b'aa' * 32)) hash2 = UInt256(data=binascii.unhexlify(b'bb' * 32)) hashes = [hash1, hash2] m = MerkleTree(hashes) depth = 1 flags = bytearray.fromhex('0000') m._TrimNode(m.Root, 1, depth, flags) self.assertNotEqual(None, m.Root.LeftChild) self.assertNotEqual(None, m.Root.RightChild)
def test_node_methods(self): hash1 = UInt256(data=binascii.unhexlify(b'aa' * 32)) hash2 = UInt256(data=binascii.unhexlify(b'bb' * 32)) hashes = [hash1, hash2] m = MerkleTree(hashes) self.assertEqual(True, m.Root.IsRoot()) self.assertEqual(False, m.Root.IsLeaf()) self.assertEqual(False, m.Root.LeftChild.IsRoot()) self.assertEqual(True, m.Root.LeftChild.IsLeaf()) # I have no acceptable test vector m.Root.LeftChild.Size()
def LoadCoins(self): coins = {} try: for coin in Coin.select(): reference = CoinReference(prev_hash=UInt256(coin.TxId), prev_index=coin.Index) output = TransactionOutput(UInt256(coin.AssetId), Fixed8(coin.Value), UInt160(coin.ScriptHash)) walletcoin = WalletCoin.CoinFromRef(reference, output, coin.State) coins[reference] = walletcoin except Exception as e: logger.error("could not load coins %s " % e) return coins
def test_trim_node1(self): hash1 = UInt256(data=binascii.unhexlify(b'aa' * 32)) hash2 = UInt256(data=binascii.unhexlify(b'bb' * 32)) hash3 = UInt256(data=binascii.unhexlify(b'cc' * 32)) hashes = [hash1, hash2, hash3] m = MerkleTree(hashes) depth = 2 flags = bytearray.fromhex( '11110000' ) # 1 byte left node , 1 byte right node 00=delete, non-00 is keep m._TrimNode(m.Root, 1, depth, flags) self.assertEqual(None, m.Root.LeftChild) self.assertEqual(None, m.Root.RightChild)
def __Build(leaves): """ Build the merkle tree. Args: leaves (list): items are of type MerkleTreeNode. Returns: MerkleTreeNode: the root node. Raises: ValueError: if the length of `leaves` is < 1 """ if len(leaves) < 1: raise ValueError('Leaves must have length') if len(leaves) == 1: return leaves[0] num_parents = int((len(leaves) + 1) / 2) parents = [MerkleTreeNode() for i in range(0, num_parents)] for i in range(0, num_parents): node = parents[i] node.LeftChild = leaves[i * 2] leaves[i * 2].Parent = node if (i * 2 + 1 == len(leaves)): node.RightChild = node.LeftChild else: node.RightChild = leaves[i * 2 + 1] leaves[i * 2 + 1].Parent = node hasharray = bytearray(node.LeftChild.Hash.ToArray() + node.RightChild.Hash.ToArray()) node.Hash = UInt256(data=Crypto.Hash256(hasharray)) return MerkleTree.__Build(parents)
def Blockchain_GetHeader(self, engine: ExecutionEngine): data = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() header = None if len(data) <= 5: height = BigInteger.FromBytes(data) if Blockchain.Default() is not None: header = Blockchain.Default().GetHeaderBy(height_or_hash=height) elif height == 0: header = Blockchain.GenesisBlock().Header elif len(data) == 32: hash = UInt256(data=data) if Blockchain.Default() is not None: header = Blockchain.Default().GetHeaderBy(height_or_hash=hash) elif hash == Blockchain.GenesisBlock().Hash: header = Blockchain.GenesisBlock().Header engine.CurrentContext.EvaluationStack.PushT(StackItem.FromInterface(header)) return True
def Blockchain_GetBlock(self, engine: ExecutionEngine): data = engine.CurrentContext.EvaluationStack.Pop() if data: data = data.GetByteArray() else: return False block = None if len(data) <= 5: height = BigInteger.FromBytes(data) if Blockchain.Default() is not None: block = Blockchain.Default().GetBlockByHeight(height) elif height == 0: block = Blockchain.GenesisBlock() elif len(data) == 32: hash = UInt256(data=data).ToBytes() if Blockchain.Default() is not None: block = Blockchain.Default().GetBlockByHash(hash=hash) elif hash == Blockchain.GenesisBlock().Hash: block = Blockchain.GenesisBlock().Header engine.CurrentContext.EvaluationStack.PushT(StackItem.FromInterface(block)) return True
def test_to_hash_array(self): hash1 = UInt256(data=binascii.unhexlify(b'aa' * 32)) hash2 = UInt256(data=binascii.unhexlify(b'bb' * 32)) hash3 = UInt256(data=binascii.unhexlify(b'cc' * 32)) hash4 = UInt256(data=binascii.unhexlify(b'dd' * 32)) hash5 = UInt256(data=binascii.unhexlify(b'ee' * 32)) hashes = [hash1, hash2, hash3, hash4, hash5] m = MerkleTree(hashes) hash_array = m.ToHashArray() # sort the array hash_array = sorted(hash_array) for i, h in enumerate(hashes): self.assertEqual(h.ToBytes(), hash_array[i].ToBytes())
def GenesisBlock() -> Block: """ Create the GenesisBlock. Returns: BLock: """ prev_hash = UInt256(data=bytearray(32)) timestamp = int( datetime(2016, 7, 15, 15, 8, 21, tzinfo=pytz.utc).timestamp()) index = 0 consensus_data = 2083236893 # Pay tribute To Bitcoin next_consensus = Blockchain.GetConsensusAddress( Blockchain.StandbyValidators()) script = Witness(bytearray(0), bytearray(PUSHT)) mt = MinerTransaction() mt.Nonce = 2083236893 output = TransactionOutput( Blockchain.SystemShare().Hash, Blockchain.SystemShare().Amount, Crypto.ToScriptHash( Contract.CreateMultiSigRedeemScript( int(len(Blockchain.StandbyValidators()) / 2) + 1, Blockchain.StandbyValidators()))) it = IssueTransaction([], [output], [], [script]) return Block( prev_hash, timestamp, index, consensus_data, next_consensus, script, [mt, Blockchain.SystemShare(), Blockchain.SystemCoin(), it], True)
def Account_GetBalance(self, engine: ExecutionEngine): account = engine.CurrentContext.EvaluationStack.Pop().GetInterface() assetId = UInt256(data=engine.CurrentContext.EvaluationStack.Pop().GetByteArray()) if account is None: return False balance = account.BalanceFor(assetId) engine.CurrentContext.EvaluationStack.PushT(balance.GetData()) return True
def Blockchain_GetTransactionHeight(self, engine: ExecutionEngine): data = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() height = -1 if Blockchain.Default() is not None: tx, height = Blockchain.Default().GetTransaction(UInt256(data=data)) engine.CurrentContext.EvaluationStack.PushT(height) return True
def Blockchain_GetTransaction(self, engine: ExecutionEngine): data = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() tx = None if Blockchain.Default() is not None: tx, height = Blockchain.Default().GetTransaction(UInt256(data=data)) engine.CurrentContext.EvaluationStack.PushT(StackItem.FromInterface(tx)) return True
def Blockchain_GetAsset(self, engine: ExecutionEngine): data = engine.CurrentContext.EvaluationStack.Pop().GetByteArray() asset = None if Blockchain.Default() is not None: asset = self.Assets.TryGet(UInt256(data=data)) if asset is None: return False engine.CurrentContext.EvaluationStack.PushT(StackItem.FromInterface(asset)) return True
def Size(self): """ Get the total size in bytes of the object. Returns: int: size. """ corrected_hashes = list( map(lambda i: UInt256(data=binascii.unhexlify(i)), self.HashStart)) return GetVarSize(corrected_hashes) + self.hash_stop.Size
def __init__(self, hash_start=[], hash_stop=UInt256()): """ Create an instance. Args: hash_start (list): a list of hash values. Each value is of the bytearray type. Note: should actually be UInt256 objects. hash_stop (UInt256): """ self.HashStart = hash_start self.HashStop = hash_stop
def Size(self): """ Get the total size in bytes of the object. Returns: int: size. """ if len(self.Hashes) > 0: if not isinstance(self.Hashes[0], UInt256): corrected_hashes = list(map(lambda i: UInt256(data=binascii.unhexlify(i)), self.Hashes)) return s.uint8 + GetVarSize(corrected_hashes)
def Hash(self): """ Get the hash of the transaction. Returns: UInt256: """ if not self.__hash: ba = bytearray(binascii.unhexlify(self.GetHashData())) hash = Crypto.Hash256(ba) self.__hash = UInt256(data=hash) return self.__hash
def test_compareto_valid(self): u1 = UInt160(b'12345678901234567890') # Same value should return 0 u2 = UIntBase(20, b'12345678901234567890') self.assertEqual(u1.CompareTo(u2), 0) # Higher digit in 'other' should return -1 u2 = UIntBase(20, b'12345678901234567891') self.assertEqual(u1.CompareTo(u2), -1) # Lower digit in 'other' should return 1 u2 = UIntBase(20, b'12345678901234567980') self.assertEqual(u1.CompareTo(u2), 1) # CompareTo across different UIntBase subclasses data = b'12345678901234567890' self.assertEqual(UInt160(data).CompareTo(UIntBase(len(data), data)), 0) self.assertEqual(UIntBase(len(data), data).CompareTo(UInt160(data)), 0) data = b'12345678901234567890123456789012' self.assertEqual(UInt256(data).CompareTo(UIntBase(len(data), data)), 0) self.assertEqual(UIntBase(len(data), data).CompareTo(UInt256(data)), 0)
def Hash(self): """ Get the hash value of the Blockbase. Returns: UInt256: containing the hash of the data. """ if not self.__hash: hashdata = self.RawData() ba = bytearray(binascii.unhexlify(hashdata)) hash = bin_dbl_sha256(ba) self.__hash = UInt256(data=hash) return self.__hash
def test_trim_node2(self): hash1 = UInt256(data=binascii.unhexlify(b'aa' * 32)) hash2 = UInt256(data=binascii.unhexlify(b'bb' * 32)) hash3 = UInt256(data=binascii.unhexlify(b'cc' * 32)) hash4 = UInt256(data=binascii.unhexlify(b'dd' * 32)) hash5 = UInt256(data=binascii.unhexlify(b'ee' * 32)) hash6 = UInt256(data=binascii.unhexlify(b'11' * 32)) hash7 = UInt256(data=binascii.unhexlify(b'22' * 32)) hash8 = UInt256(data=binascii.unhexlify(b'33' * 32)) hash9 = UInt256(data=binascii.unhexlify(b'44' * 32)) hashes = [ hash1, hash2, hash3, hash4, hash5, hash6, hash7, hash8, hash9 ] m = MerkleTree(hashes) depth = 3 flags = bytearray.fromhex('111100000000') m._TrimNode(m.Root, 1, depth, flags) self.assertEqual(None, m.Root.LeftChild) self.assertEqual(None, m.Root.RightChild)
def test_compareto_invalid_datatype(self): u1 = UIntBase(20, b'12345678901234567890') with self.assertRaises(TypeError): self.assertEqual(u1.CompareTo('asd'), 0) with self.assertRaises(TypeError): self.assertEqual(u1.CompareTo(b'asd'), 0) with self.assertRaises(TypeError): self.assertEqual(u1.CompareTo(123), 0) # Cannot compare uints with different lengths with self.assertRaises(ValueError): a = UInt256(b'12345678901234567890123456789012') b = UIntBase(20, b'12345678901234567890') a.CompareTo(b)
def test_various(self): self.assertEqual(BinaryWriter.swap32(123), 2063597568) self.assertEqual(BinaryWriter.swap32(2063597568), 123) self.assertEqual(BinaryWriter.convert_to_uint160(123), '00000000000001111011') self.assertEqual(BinaryWriter.convert_to_uint256(123), '00000000000000000000000001111011') def bw_writebyte(stream_data): stream = BytesIO() bw = BinaryWriter.BinaryWriter(stream) bw.WriteByte(stream_data) stream.seek(0) return stream self.assertEqual(bw_writebyte(b'\x00').read(1), b'\x00') self.assertEqual(bw_writebyte('1').read(1), b'1') self.assertEqual(bw_writebyte(1).read(1), b'\x01') def bw_setup(): stream = BytesIO() bw = BinaryWriter.BinaryWriter(stream) return stream, bw stream, bw = bw_setup() bw.pack('c', b'\x41') stream.seek(0) self.assertEqual(stream.read(1), b'A') stream, bw = bw_setup() bw.WriteChar(b'\x41') stream.seek(0) self.assertEqual(stream.read(1), b'A') stream, bw = bw_setup() bw.WriteFloat(123.41) stream.seek(0) self.assertEqual(stream.readline(), b'\xec\xd1\xf6B') stream, bw = bw_setup() bw.WriteDouble(976) stream.seek(0) self.assertEqual(stream.readline(), b'\x00\x00\x00\x00\x00\x80\x8e@') stream, bw = bw_setup() bw.WriteUInt8(167) stream.seek(0) self.assertEqual(stream.readline(), b'\xa7') stream, bw = bw_setup() bw.WriteBool(True) stream.seek(0) self.assertEqual(stream.readline(), b'\x01') stream, bw = bw_setup() bw.WriteBool(False) stream.seek(0) self.assertEqual(stream.readline(), b'\x00') stream, bw = bw_setup() bw.WriteInt8(17) stream.seek(0) self.assertEqual(stream.readline(), b'\x11') stream, bw = bw_setup() bw.WriteInt16(12345) stream.seek(0) self.assertEqual(stream.readline(), b'90') stream, bw = bw_setup() bw.WriteUInt16(12345) stream.seek(0) self.assertEqual(stream.readline(), b'90') stream, bw = bw_setup() bw.WriteUInt16(32767 * 2) stream.seek(0) self.assertEqual(stream.readline(), b'\xfe\xff') stream, bw = bw_setup() bw.WriteInt32(32767 * 2 * 2) stream.seek(0) self.assertEqual(stream.readline(), b'\xfc\xff\x01\x00') stream, bw = bw_setup() bw.WriteUInt32(32767 * 2 * 2) stream.seek(0) self.assertEqual(stream.readline(), b'\xfc\xff\x01\x00') stream, bw = bw_setup() bw.WriteInt64(32767 * 2 * 2) stream.seek(0) self.assertEqual(stream.readline(), b'\xfc\xff\x01\x00\x00\x00\x00\x00') stream, bw = bw_setup() bw.WriteUInt64(32767 * 2 * 2) stream.seek(0) self.assertEqual(stream.readline(), b'\xfc\xff\x01\x00\x00\x00\x00\x00') stream, bw = bw_setup() bw.WriteUInt160(UInt160(b'12345678901234567890')) stream.seek(0) self.assertEqual(stream.readline(), b'\x124Vx\x90\x124Vx\x90') with self.assertRaises(TypeError): bw.WriteUInt160(123) stream, bw = bw_setup() bw.WriteUInt256(UInt256(b'12345678901234567890123456789012')) stream.seek(0) self.assertEqual(stream.readline(), b'\x124Vx\x90\x124Vx\x90\x124Vx\x90\x12') with self.assertRaises(TypeError): bw.WriteUInt256(123) with self.assertRaises(TypeError): bw.WriteVarInt("x") with self.assertRaises(ValueError): bw.WriteVarInt(-1) stream, bw = bw_setup() bw.WriteVarInt(12) stream.seek(0) self.assertEqual(stream.readline(), b'\x0c') stream, bw = bw_setup() bw.WriteVarInt(0xff) stream.seek(0) self.assertEqual(stream.readline(), b'\xfd\xff\x00') stream, bw = bw_setup() bw.WriteVarInt(0xffffff) stream.seek(0) self.assertEqual(stream.readline(), b'\xfe\xff\xff\xff\x00') stream, bw = bw_setup() bw.WriteVarInt(0xFFFFFFFFFF) stream.seek(0) self.assertEqual(stream.readline(), b'\xff\xff\xff\xff\xff\xff\x00\x00\x00') stream, bw = bw_setup() bw.WriteVarBytes(b'123') stream.seek(0) self.assertEqual(stream.readline(), b'\x03123') stream, bw = bw_setup() bw.WriteFixedString("test", 10) stream.seek(0) self.assertEqual(stream.readline(), b'test\x00\x00\x00\x00\x00\x00') stream, bw = bw_setup() bw.WriteSerializableArray(None) stream.seek(0) self.assertEqual(stream.readline(), b'\x00') # stream, bw = bw_setup() # val = [b'x' * 64 for _ in range(2000)] # bw.Write2000256List(val) # stream.seek(0) # self.assertEqual(stream.readline(), b'\x00') stream, bw = bw_setup() bw.WriteHashes([b'12', b'45']) stream.seek(0) self.assertEqual(stream.readline(), b'\x02\x12E') stream, bw = bw_setup() bw.WriteFixed8(Fixed8(100)) stream.seek(0) self.assertEqual(stream.readline(), b'd\x00\x00\x00\x00\x00\x00\x00') # stream, bw = bw_setup() test_value = "my_test_string" bw.WriteVarString(test_value) stream.seek(0) result = stream.readline() # note \x0e is the length of `test_value` that's appended in front self.assertEqual(b'\x0emy_test_string', result)
def example1(): neo_asset_id = Blockchain.GetSystemShare().Hash gas_asset_id = Blockchain.GetSystemCoin().Hash source_address = "AJQ6FoaSXDFzA6wLnyZ1nFN7SGSN2oNTc3" source_script_hash = address_to_scripthash(source_address) destination_address = "Ad9A1xPbuA5YBFr1XPznDwBwQzdckAjCev" destination_script_hash = address_to_scripthash(destination_address) # Let's start with building a ContractTransaction # The constructor already sets the correct `Type` and `Version` fields, so we do not have to worry about that contract_tx = ContractTransaction() # Since we are building a raw transaction, we will add the raw_tx flag contract_tx.raw_tx = True # Next we can add Attributes if we want. Again the various types are described in point 4. of the main link above # We will add a simple "description" contract_tx.Attributes.append( TransactionAttribute(usage=TransactionAttributeUsage.Description, data="My raw contract transaction description")) # The next field we will set are the inputs. The inputs neo-python expects are of the type ``CoinReference`` # To create these inputs we will need the usual `PrevHash` and `PrevIndex` values. # You can get the required data by using e.g. the neoscan.io API: https://api.neoscan.io/docs/index.html#api-v1-get-3 # The `PrevHash` field equals to neoscan's `balance.unspent[index].txid` key, and `PrevIndex` comes from `balance.unspent[index].n` # It is up to the transaction creator to make sure that the sum of all input ``value`` fields is equal to or bigger than the amount that's intended to be send # The below values are taken from data out of the `neo-test1-w.wallet` fixture wallet (a wallet neo-python uses for internal testing) input1 = CoinReference(prev_hash=UInt256(data=binascii.unhexlify( '949354ea0a8b57dfee1e257a1aedd1e0eea2e5837de145e8da9c0f101bfccc8e')), prev_index=1) contract_tx.inputs = [input1] # Next we will create the outputs. # The above input has a value of 50. We will create 2 outputs. # 1 output for sending 3 NEO to a specific destination address send_to_destination_output = TransactionOutput( AssetId=neo_asset_id, Value=Fixed8.FromDecimal(3), script_hash=destination_script_hash) # and a second output for sending the change back to ourselves return_change_output = TransactionOutput(AssetId=neo_asset_id, Value=Fixed8.FromDecimal(47), script_hash=source_script_hash) contract_tx.outputs = [send_to_destination_output, return_change_output] # at this point we've build our unsigned transaction and it's time to sign it before we get the raw output that we can send to the network via RPC # we need to create a Wallet instance for helping us with signing wallet = UserWallet.Create('path', to_aes_key('mypassword'), generate_default_key=False) # if you have a WIF use the following # this WIF comes from the `neo-test1-w.wallet` fixture wallet private_key = KeyPair.PrivateKeyFromWIF( "Ky94Rq8rb1z8UzTthYmy1ApbZa9xsKTvQCiuGUZJZbaDJZdkvLRV") # if you have a NEP2 encrypted key use the following instead # private_key = KeyPair.PrivateKeyFromNEP2("NEP2 key string", "password string") # we add the key to our wallet wallet.CreateKey(private_key) # and now we're ready to sign context = ContractParametersContext(contract_tx) wallet.Sign(context) contract_tx.scripts = context.GetScripts() print(contract_tx.Hash.ToString()) raw_tx = contract_tx.ToArray() return raw_tx
def test_initialization(self): u0 = UInt256() self.assertEqual(hash(u0), 0) u1 = UInt256(b'12345678901234567890123456789012') self.assertEqual(hash(u1), 875770417)
class EventTestCase(TestCase): contract_hash = UInt160(data=bytearray(b'\x11\xc4\xd1\xf4\xfb\xa6\x19\xf2b\x88p\xd3n:\x97s\xe8tp[')) event_tx = UInt256(data=bytearray(b'\x90\xe4\xf1\xbbb\x8e\xf1\x07\xde\xe9\xf0\xd2\x12\xd1w\xbco\x844\x07=\x1b\xa7\x1f\xa7\x94`\x0b\xb4\x88|K')) addr_to = b')\x96S\xb5\xe3e\xcb3\xb4\xea:\xd1\xd7\xe1\xb3\xf5\xe6\x81N/' addr_from = b'4\xd0=k\x80TF\x9e\xa8W\x83\xfa\x9eIv\x0b\x9bs\x9d\xb6' def test_1_serialize_runtime_log(self): sc = SmartContractEvent(SmartContractEvent.RUNTIME_LOG, ContractParameter(ContractParameterType.Array, []), self.contract_hash, 99999, self.event_tx, True, False) stream = StreamManager.GetStream() writer = BinaryWriter(stream) sc.Serialize(writer) out = bytes(stream.getvalue()) self.assertEqual(out, b'\x19SmartContract.Runtime.Log\x11\xc4\xd1\xf4\xfb\xa6\x19\xf2b\x88p\xd3n:\x97s\xe8tp[\x9f\x86\x01\x00\x90\xe4\xf1\xbbb\x8e\xf1\x07\xde\xe9\xf0\xd2\x12\xd1w\xbco\x844\x07=\x1b\xa7\x1f\xa7\x94`\x0b\xb4\x88|K') StreamManager.ReleaseStream(stream) new_event = SmartContractEvent.FromByteArray(out) self.assertEqual(new_event.event_type, sc.event_type) self.assertEqual(new_event.contract_hash, sc.contract_hash) self.assertEqual(new_event.test_mode, sc.test_mode) self.assertEqual(new_event.tx_hash, sc.tx_hash) self.assertEqual(new_event.block_number, sc.block_number) def test_2_serialize_notify_no_payload(self): sc = SmartContractEvent(SmartContractEvent.RUNTIME_NOTIFY, ContractParameter(ContractParameterType.Array, []), self.contract_hash, 99, self.event_tx, True, False) stream = StreamManager.GetStream() writer = BinaryWriter(stream) sc.Serialize(writer) out = bytes(stream.getvalue()) self.assertEqual(out, b'\x1cSmartContract.Runtime.Notify\x11\xc4\xd1\xf4\xfb\xa6\x19\xf2b\x88p\xd3n:\x97s\xe8tp[c\x00\x00\x00\x90\xe4\xf1\xbbb\x8e\xf1\x07\xde\xe9\xf0\xd2\x12\xd1w\xbco\x844\x07=\x1b\xa7\x1f\xa7\x94`\x0b\xb4\x88|K') StreamManager.ReleaseStream(stream) new_event = SmartContractEvent.FromByteArray(out) self.assertEqual(new_event.event_type, sc.event_type) self.assertEqual(new_event.contract_hash, sc.contract_hash) self.assertEqual(new_event.test_mode, sc.test_mode) self.assertEqual(new_event.tx_hash, sc.tx_hash) self.assertEqual(new_event.block_number, sc.block_number) def test_2_serialize_single_notify_payload(self): sc = NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, ContractParameter(ContractParameterType.Array, [ContractParameter(ContractParameterType.String, b'hello')]), self.contract_hash, 99, self.event_tx, True, False) stream = StreamManager.GetStream() writer = BinaryWriter(stream) sc.Serialize(writer) out = bytes(stream.getvalue()) self.assertEqual(out, b'\x1cSmartContract.Runtime.Notify\x11\xc4\xd1\xf4\xfb\xa6\x19\xf2b\x88p\xd3n:\x97s\xe8tp[c\x00\x00\x00\x90\xe4\xf1\xbbb\x8e\xf1\x07\xde\xe9\xf0\xd2\x12\xd1w\xbco\x844\x07=\x1b\xa7\x1f\xa7\x94`\x0b\xb4\x88|K\x05hello') StreamManager.ReleaseStream(stream) new_event = SmartContractEvent.FromByteArray(out) self.assertEqual(new_event.event_type, sc.event_type) self.assertEqual(new_event.contract_hash, sc.contract_hash) self.assertEqual(new_event.test_mode, sc.test_mode) self.assertEqual(new_event.tx_hash, sc.tx_hash) self.assertEqual(new_event.block_number, sc.block_number) self.assertEqual(new_event.notify_type, b'hello') self.assertEqual(new_event.AddressFrom, None) self.assertEqual(new_event.AddressTo, None) self.assertEqual(new_event.Amount, 0) self.assertEqual(new_event.is_standard_notify, False) def test_3_serialize_single_transfer_notify_payload(self): sc = NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, ContractParameter(ContractParameterType.Array, [ContractParameter(ContractParameterType.String, b'transfer')]), self.contract_hash, 99, self.event_tx, True, False) stream = StreamManager.GetStream() writer = BinaryWriter(stream) sc.Serialize(writer) out = bytes(stream.getvalue()) StreamManager.ReleaseStream(stream) new_event = SmartContractEvent.FromByteArray(out) self.assertEqual(new_event.event_type, sc.event_type) self.assertEqual(new_event.contract_hash, sc.contract_hash) self.assertEqual(new_event.test_mode, sc.test_mode) self.assertEqual(new_event.tx_hash, sc.tx_hash) self.assertEqual(new_event.block_number, sc.block_number) self.assertEqual(new_event.notify_type, b'transfer') self.assertEqual(new_event.AddressFrom, None) self.assertEqual(new_event.AddressTo, None) self.assertEqual(new_event.Amount, 0) self.assertEqual(new_event.is_standard_notify, False) self.assertEqual(new_event.ShouldPersist, False) def test_4_serialize_full_transfer_notify_payload(self): payload = ContractParameter(ContractParameterType.Array, [ ContractParameter(ContractParameterType.String, b'transfer'), ContractParameter(ContractParameterType.ByteArray, self.addr_to), ContractParameter(ContractParameterType.ByteArray, self.addr_from), ContractParameter(ContractParameterType.Integer, 123000) ]) sc = NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, payload, self.contract_hash, 91349, self.event_tx, True, False) stream = StreamManager.GetStream() writer = BinaryWriter(stream) sc.Serialize(writer) out = bytes(stream.getvalue()) StreamManager.ReleaseStream(stream) new_event = SmartContractEvent.FromByteArray(out) self.assertEqual(new_event.event_type, sc.event_type) self.assertEqual(new_event.contract_hash, sc.contract_hash) self.assertEqual(new_event.test_mode, sc.test_mode) self.assertEqual(new_event.tx_hash, sc.tx_hash) self.assertEqual(new_event.block_number, sc.block_number) self.assertEqual(new_event.notify_type, b'transfer') self.assertEqual(new_event.AddressTo, 'ALb8FEhEmtSqv97fuNVuoLmcmrSKckffRf') self.assertEqual(new_event.AddressFrom, 'AKZmSGPD7ytJBbxpRPmobYGLNxdWH3Jiqs') self.assertEqual(new_event.Amount, 123000) self.assertEqual(new_event.is_standard_notify, True) def test_5_serialize_full_refund_payload(self): payload = ContractParameter(ContractParameterType.Array, [ ContractParameter(ContractParameterType.String, b'refund'), ContractParameter(ContractParameterType.ByteArray, self.addr_to), ContractParameter(ContractParameterType.Integer, 123000) ]) sc = NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, payload, self.contract_hash, 91349, self.event_tx, True, False) stream = StreamManager.GetStream() writer = BinaryWriter(stream) sc.Serialize(writer) out = bytes(stream.getvalue()) StreamManager.ReleaseStream(stream) new_event = SmartContractEvent.FromByteArray(out) self.assertEqual(new_event.event_type, sc.event_type) self.assertEqual(new_event.contract_hash, sc.contract_hash) self.assertEqual(new_event.test_mode, sc.test_mode) self.assertEqual(new_event.tx_hash, sc.tx_hash) self.assertEqual(new_event.block_number, sc.block_number) self.assertEqual(new_event.notify_type, b'refund') self.assertEqual(new_event.AddressTo, 'AKZmSGPD7ytJBbxpRPmobYGLNxdWH3Jiqs') self.assertEqual(new_event.addr_from, sc.contract_hash) self.assertEqual(new_event.Amount, 123000) self.assertEqual(new_event.is_standard_notify, True) def test_6_serialize_full_approve_payload(self): payload = ContractParameter(ContractParameterType.Array, [ ContractParameter(ContractParameterType.String, b'approve'), ContractParameter(ContractParameterType.ByteArray, self.addr_to), ContractParameter(ContractParameterType.ByteArray, self.addr_from), ContractParameter(ContractParameterType.ByteArray, b'x\xe0\x01') ]) sc = NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, payload, self.contract_hash, 91349, self.event_tx, True, False) stream = StreamManager.GetStream() writer = BinaryWriter(stream) sc.Serialize(writer) out = bytes(stream.getvalue()) StreamManager.ReleaseStream(stream) new_event = SmartContractEvent.FromByteArray(out) self.assertEqual(new_event.event_type, sc.event_type) self.assertEqual(new_event.contract_hash, sc.contract_hash) self.assertEqual(new_event.test_mode, sc.test_mode) self.assertEqual(new_event.tx_hash, sc.tx_hash) self.assertEqual(new_event.block_number, sc.block_number) self.assertEqual(new_event.notify_type, b'approve') self.assertEqual(new_event.AddressFrom, 'AKZmSGPD7ytJBbxpRPmobYGLNxdWH3Jiqs') self.assertEqual(new_event.AddressTo, 'ALb8FEhEmtSqv97fuNVuoLmcmrSKckffRf') self.assertEqual(new_event.Amount, 123000) self.assertEqual(new_event.is_standard_notify, True) self.assertEqual(new_event.ShouldPersist, True)
class NotificationDBTestCase(TestCase): contract_hash = UInt160(data=bytearray(b'\x11\xc4\xd1\xf4\xfb\xa6\x19\xf2b\x88p\xd3n:\x97s\xe8tp[')) event_tx = UInt256(data=bytearray(b'\x90\xe4\xf1\xbbb\x8e\xf1\x07\xde\xe9\xf0\xd2\x12\xd1w\xbco\x844\x07=\x1b\xa7\x1f\xa7\x94`\x0b\xb4\x88|K')) addr_to = b')\x96S\xb5\xe3e\xcb3\xb4\xea:\xd1\xd7\xe1\xb3\xf5\xe6\x81N/' addr_from = b'4\xd0=k\x80TF\x9e\xa8W\x83\xfa\x9eIv\x0b\x9bs\x9d\xb6' @classmethod def setUpClass(cls): settings.NOTIFICATION_DB_PATH = os.path.join(settings.DATA_DIR_PATH, f"fixtures/{str(uuid1())}") ndb = NotificationDB.instance() ndb.start() @classmethod def tearDownClass(cls): NotificationDB.instance().close() shutil.rmtree(settings.NOTIFICATION_DB_PATH) def test_1_notify_should_not_persist(self): sc = NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, ContractParameter(ContractParameterType.Array, []), self.contract_hash, 99, self.event_tx, True, False) ndb = NotificationDB.instance() ndb.on_smart_contract_event(sc) self.assertEqual(ndb.current_events, []) def test_2_persist_isnt_notify_event(self): sc = SmartContractEvent(SmartContractEvent.RUNTIME_NOTIFY, ContractParameter(ContractParameterType.Array, []), self.contract_hash, 99, self.event_tx, True, False) ndb = NotificationDB.instance() ndb.on_smart_contract_event(sc) self.assertEqual(ndb.current_events, []) def test_3_should_persist(self): payload = ContractParameter(ContractParameterType.Array, [ ContractParameter(ContractParameterType.String, b'transfer'), ContractParameter(ContractParameterType.ByteArray, self.addr_to), ContractParameter(ContractParameterType.ByteArray, self.addr_from), ContractParameter(ContractParameterType.Integer, 123000) ]) sc = NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, payload, self.contract_hash, 91349, self.event_tx, True, False) ndb = NotificationDB.instance() ndb.on_smart_contract_event(sc) self.assertEqual(len(ndb.current_events), 1) ndb.on_persist_completed(None) def test_4_should_persist(self): ndb = NotificationDB.instance() self.assertEqual(len(ndb.current_events), 0) payload = ContractParameter(ContractParameterType.Array, [ ContractParameter(ContractParameterType.String, b'transfer'), ContractParameter(ContractParameterType.ByteArray, self.addr_to), ContractParameter(ContractParameterType.ByteArray, self.addr_from), ContractParameter(ContractParameterType.Integer, 123000) ]) sc = NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, payload, self.contract_hash, 91349, self.event_tx, True, True) ndb.on_smart_contract_event(sc) self.assertEqual(len(ndb.current_events), 0) def test_4_notification_lookup(self): ndb = NotificationDB.instance() events = ndb.get_by_block(91349) self.assertEqual(len(events), 1) def test_5_addr_from_lookup(self): ndb = NotificationDB.instance() events = ndb.get_by_addr('ALb8FEhEmtSqv97fuNVuoLmcmrSKckffRf') self.assertEqual(len(events), 1) evt = events[0] # type:NotifyEvent self.assertEqual(evt.AddressTo, 'ALb8FEhEmtSqv97fuNVuoLmcmrSKckffRf') def test_6_addr_to_lookup(self): ndb = NotificationDB.instance() events = ndb.get_by_addr('AKZmSGPD7ytJBbxpRPmobYGLNxdWH3Jiqs') self.assertEqual(len(events), 1) evt = events[0] # type:NotifyEvent self.assertEqual(evt.AddressFrom, 'AKZmSGPD7ytJBbxpRPmobYGLNxdWH3Jiqs') def test_7_lookup_addr_by_script_hash(self): ndb = NotificationDB.instance() sh = UInt160(data=b')\x96S\xb5\xe3e\xcb3\xb4\xea:\xd1\xd7\xe1\xb3\xf5\xe6\x81N/') events = ndb.get_by_addr(sh) self.assertEqual(len(events), 1) def test_8_lookup_should_be_empty(self): ndb = NotificationDB.instance() events = ndb.get_by_block(123) self.assertEqual(len(events), 0) def test_9_lookup_should_be_empty(self): ndb = NotificationDB.instance() sh = UInt160(data=b')\x96S\xb5\xe3e\xcb3\xb4\xea:\xd1\xd7\xe1\xb3\xf5\xe6\x82N/') events = ndb.get_by_addr(sh) self.assertEqual(len(events), 0) def test_should_persist_mint_event(self): payload = ContractParameter(ContractParameterType.Array, [ ContractParameter(ContractParameterType.String, b'mint'), ContractParameter(ContractParameterType.ByteArray, self.addr_to), ContractParameter(ContractParameterType.Integer, 123000) ]) sc = NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, payload, self.contract_hash, 91349, self.event_tx, True, False) ndb = NotificationDB.instance() ndb.on_smart_contract_event(sc) self.assertEqual(len(ndb.current_events), 1) ndb.on_persist_completed(None)
def test_initialization_invalid(self): with self.assertRaises(ValueError): UInt256(b'12345') with self.assertRaises(TypeError): UInt256('12345678901234567890123456789012')
def ExecutionCompleted(self, engine, success, error=None): height = Blockchain.Default().Height + 1 tx_hash = None if engine.ScriptContainer: tx_hash = engine.ScriptContainer.Hash if not tx_hash: tx_hash = UInt256(data=bytearray(32)) entry_script = None try: # get the first script that was executed # this is usually the script that sets up the script to be executed entry_script = UInt160(data=engine.ExecutedScriptHashes[0]) # ExecutedScriptHashes[1] will usually be the first contract executed if len(engine.ExecutedScriptHashes) > 1: entry_script = UInt160(data=engine.ExecutedScriptHashes[1]) except Exception as e: logger.error("Could not get entry script: %s " % e) payload = ContractParameter(ContractParameterType.Array, value=[]) for item in engine.ResultStack.Items: payload.Value.append(ContractParameter.ToParameter(item)) if success: # dispatch all notify events, along with the success of the contract execution for notify_event_args in self.notifications: self.events_to_dispatch.append(NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, notify_event_args.State, notify_event_args.ScriptHash, height, tx_hash, success, engine.testMode)) if engine.Trigger == Application: self.events_to_dispatch.append(SmartContractEvent(SmartContractEvent.EXECUTION_SUCCESS, payload, entry_script, height, tx_hash, success, engine.testMode)) else: self.events_to_dispatch.append(SmartContractEvent(SmartContractEvent.VERIFICATION_SUCCESS, payload, entry_script, height, tx_hash, success, engine.testMode)) else: # when a contract exits in a faulted state # we should display that in the notification if not error: error = 'Execution exited in a faulted state. Any payload besides this message contained in this event is the contents of the EvaluationStack of the current script context.' payload.Value.append(ContractParameter(ContractParameterType.String, error)) # If we do not add the eval stack, then exceptions that are raised in a contract # are not displayed to the event consumer [payload.Value.append(ContractParameter.ToParameter(item)) for item in engine.CurrentContext.EvaluationStack.Items] if engine.Trigger == Application: self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.EXECUTION_FAIL, payload, entry_script, height, tx_hash, success, engine.testMode)) else: self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.VERIFICATION_FAIL, payload, entry_script, height, tx_hash, success, engine.testMode)) self.notifications = []