def test_6_serialize_full_approve_payload(self): sc = NotifyEvent( SmartContractEvent.RUNTIME_NOTIFY, [b'approve', self.addr_to, self.addr_from, b'x\xe0\x01'], 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)
def test_2_serialize_single_notify_payload(self): sc = NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, [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, [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_5_serialize_full_refund_payload(self): sc = NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, [b'refund', self.addr_to, BigInteger(123000)], 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_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 Runtime_Notify(self, engine): state = engine.EvaluationStack.Pop() # Build and emit smart contract event state_py = stack_item_to_py(state) payload = state_py if isinstance(state_py, list) else [ state_py ] # Runtime.Notify payload must be a list args = NotifyEventArgs( engine.ScriptContainer, UInt160(data=engine.CurrentContext.ScriptHash()), payload) message = payload[0] if len(payload) > 0 else payload engine.write_log(str(message)) self.notifications.append(args) if settings.emit_notify_events_on_sc_execution_error: # emit Notify events even if the SC execution might fail. tx_hash = engine.ScriptContainer.Hash height = Blockchain.Default().Height + 1 success = None self.events_to_dispatch.append( NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, args.State, args.ScriptHash, height, tx_hash, success, engine.testMode)) return True
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 ExecutionCompleted(self, engine, success, error=None): height = Blockchain.Default().Height tx_hash = engine.ScriptContainer.Hash 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 = [] for item in engine.EvaluationStack.Items: payload_item = stack_item_to_py(item) payload.append(payload_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: if engine.Trigger == Application: self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.EXECUTION_FAIL, [payload, error, engine._VMState], entry_script, height, tx_hash, success, engine.testMode)) else: self.events_to_dispatch.append( SmartContractEvent(SmartContractEvent.VERIFICATION_FAIL, [payload, error, engine._VMState], entry_script, height, tx_hash, success, engine.testMode)) self.notifications = []
def dispatch_smart_contract_notify(event_type, event_payload, contract_hash, block_number, tx_hash, execution_success=False, test_mode=False): notify_event = NotifyEvent(event_type, event_payload, contract_hash, block_number, tx_hash, execution_success, test_mode) events.emit(event_type, notify_event)
def test_should_persist_mint_event(self): sc = NotifyEvent( SmartContractEvent.RUNTIME_NOTIFY, [b'mint', self.addr_to, BigInteger(123000)], 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) sc = NotifyEvent( SmartContractEvent.RUNTIME_NOTIFY, [b'transfer', self.addr_to, self.addr_from, BigInteger(123000)], self.contract_hash, 91349, self.event_tx, True, True) ndb.on_smart_contract_event(sc) self.assertEqual(len(ndb.current_events), 0)
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 Runtime_Notify(self, engine: ExecutionEngine): state = engine.CurrentContext.EvaluationStack.Pop() payload = ContractParameter.ToParameter(state) args = NotifyEventArgs( engine.ScriptContainer, UInt160(data=engine.CurrentContext.ScriptHash()), payload) self.notifications.append(args) if settings.emit_notify_events_on_sc_execution_error: # emit Notify events even if the SC execution might fail. tx_hash = engine.ScriptContainer.Hash height = GetBlockchain().Height + 1 success = None self.events_to_dispatch.append( NotifyEvent(SmartContractEvent.RUNTIME_NOTIFY, payload, args.ScriptHash, height, tx_hash, success, engine.testMode)) return True
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 = []
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: payload.Value.append( ContractParameter(ContractParameterType.String, error)) payload.Value.append( ContractParameter(ContractParameterType.String, engine._VMState)) 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 = []