def transfer_helper(self, contract: contracts.NativeContract, from_account: types.UInt160, to_account: types.UInt160, amount: vm.BigInteger): engine = test_engine(has_snapshot=True) block = test_block(0) # set or we won't pass the native deploy call engine.snapshot.persisting_block = block engine.invocation_stack.pop() # we no longer need the default script engine.script_container = TestIVerifiable() engine.script_container.script_hashes = [from_account] sb = vm.ScriptBuilder() sb.emit(vm.OpCode.PUSHNULL) sb.emit_push(amount) sb.emit_push(to_account.to_array()) sb.emit_push(from_account.to_array()) sb.emit_push(4) sb.emit(vm.OpCode.PACK) sb.emit_push(15) # callflags sb.emit_push(b'transfer') sb.emit_push(contract.hash.to_array()) sb.emit_syscall(syscall_name_to_int("System.Contract.Call")) engine.load_script(vm.Script(sb.to_array())) nef = contracts.NEF(script=sb.to_array()) manifest = contracts.ContractManifest("test_contract") contract_state = contracts.ContractState( 1, nef, manifest, 0, contract_hash(from_account, nef.checksum, manifest.name)) engine.snapshot.contracts.put(contract_state) return engine
def test_gettime(self): engine = test_engine(has_container=False, has_snapshot=True) b = test_block() engine.snapshot.persisting_block = b engine.invoke_syscall_by_name("System.Runtime.GetTime") item = engine.pop() self.assertIsInstance(item, vm.IntegerStackItem) self.assertEqual(vm.IntegerStackItem(b.timestamp), item)
def test_policy_block_account_and_is_blocked(self): engine = test_engine(has_snapshot=True) block = test_block(0) # set or we won't pass the native deploy call engine.snapshot.persisting_block = block sb = vm.ScriptBuilder() # set or we won't pass the check_comittee() in the policy contract function implementations engine.script_container = TestIVerifiable() validator = settings.standby_committee[0] script_hash = to_script_hash( contracts.Contract.create_multisig_redeemscript(1, [validator])) engine.script_container.script_hashes = [script_hash] # first we setup the stack for calling `blockAccount` # push data to create a vm.Array holding 20 bytes for the UInt160 Account parameter of the _block_account function. sb.emit_push(b'\x11' * 20) sb.emit(vm.OpCode.PUSH1) sb.emit(vm.OpCode.PACK) sb.emit_push(15) # call flags sb.emit_push("blockAccount") sb.emit_push(contracts.PolicyContract().hash.to_array()) sb.emit_syscall(syscall_name_to_int("System.Contract.Call")) # next we call `isBlocked` sb.emit_push(b'\x11' * 20) sb.emit(vm.OpCode.PUSH1) sb.emit(vm.OpCode.PACK) sb.emit_push(15) # call flags sb.emit_push("isBlocked") sb.emit_push(contracts.PolicyContract().hash.to_array()) sb.emit_syscall(syscall_name_to_int("System.Contract.Call")) script = vm.Script(sb.to_array()) engine.load_script(script) # storing the current script in a contract otherwise "System.Contract.Call" will fail its checks nef = contracts.NEF(script=sb.to_array()) manifest = contracts.ContractManifest("test_contract") sender = engine.script_container.script_hashes[0] contract = contracts.ContractState( 1, nef, manifest, 0, contract_hash(sender, nef.checksum, manifest.name)) engine.snapshot.contracts.put(contract) engine.execute() self.assertEqual(vm.VMState.HALT, engine.state) self.assertEqual(2, len(engine.result_stack)) get_is_blocked_result = engine.result_stack.pop() set_blocked_account_result = engine.result_stack.pop() self.assertTrue(set_blocked_account_result.to_boolean()) self.assertTrue(get_is_blocked_result.to_boolean())
def test_total_supply(self): engine = test_engine(has_snapshot=True) block = test_block(0) # set or we won't pass the native deploy call engine.snapshot.persisting_block = block gas = contracts.GasToken() neo = contracts.NeoToken() # this is now the initial stored value + the result of the post_persist event (=committee reward added) expected_total_gas_supply = vm.BigInteger(3000000050000000) self.assertEqual(expected_total_gas_supply, gas.total_supply(engine.snapshot)) self.assertEqual(100_000_000, neo.total_supply(engine.snapshot))
def test_policy_setters_fail_without_signatures(self): # cover set functions where check_committee fails policy = contracts.PolicyContract() engine = test_engine(has_snapshot=True) block = test_block(0) engine.snapshot.persisting_block = block engine.script_container = TestIVerifiable() with self.assertRaises(ValueError) as context: policy._set_fee_per_byte(engine, 0) self.assertEqual("Check committee failed", str(context.exception)) self.assertFalse(policy._block_account(engine, None)) self.assertFalse(policy._unblock_account(engine, None))
def test_transfer_negative_amount(self): engine = test_engine(has_snapshot=True, default_script=False) engine.load_script(vm.Script(contracts.GasToken().script)) block = test_block(0) # set or we won't pass the native deploy call engine.snapshot.persisting_block = block gas = contracts.GasToken() with self.assertRaises(ValueError) as context: gas.transfer(engine, types.UInt160.zero(), types.UInt160.zero(), vm.BigInteger(-1), vm.NullStackItem()) self.assertEqual("Can't transfer a negative amount", str(context.exception))
def test_burn(self): engine = test_engine(has_snapshot=True) block = test_block(0) # set or we won't pass the native deploy call engine.snapshot.persisting_block = block gas = contracts.GasToken() with self.assertRaises(ValueError) as context: gas.burn(engine, self.validator_account, vm.BigInteger(-1)) self.assertEqual("Can't burn a negative amount", str(context.exception)) default_gas = 30_000_000 self.assertEqual( default_gas, gas.balance_of(engine.snapshot, self.validator_account) / gas.factor) gas.burn(engine, self.validator_account, vm.BigInteger(0)) self.assertEqual( default_gas, gas.balance_of(engine.snapshot, self.validator_account) / gas.factor) with self.assertRaises(ValueError) as context: gas.burn(engine, self.validator_account, vm.BigInteger(default_gas + 1) * gas.factor) self.assertEqual( "Insufficient balance. Requesting to burn 3000000100000000, available 3000000000000000", str(context.exception)) # burn a bit gas.burn(engine, self.validator_account, vm.BigInteger(10) * gas.factor) remaining_balance = int( gas.balance_of(engine.snapshot, self.validator_account) / gas.factor) self.assertEqual(default_gas - 10, remaining_balance) # now burn it all gas.burn(engine, self.validator_account, vm.BigInteger(remaining_balance) * gas.factor) self.assertEqual( 0, gas.balance_of(engine.snapshot, self.validator_account) / gas.factor)
def test_policy_unblock_account(self): engine = test_engine(has_snapshot=True) block = test_block(0) engine.snapshot.persisting_block = block # we must add a script_container with valid signature to pass the check_comittee() validation check # in the function itself engine.script_container = TestIVerifiable() validator = settings.standby_committee[0] script_hash = to_script_hash( contracts.Contract.create_multisig_redeemscript(1, [validator])) engine.script_container.script_hashes = [script_hash] policy = contracts.PolicyContract() account_not_found = types.UInt160(data=b'\x11' * 20) account = types.UInt160.zero() self.assertTrue(policy._block_account(engine, account)) self.assertFalse(policy._unblock_account(engine, account_not_found)) self.assertTrue(policy._unblock_account(engine, account)) storage_key = policy.key_blocked_account + account storage_item = engine.snapshot.storages.try_get(storage_key) self.assertIsNone(storage_item)
def test_balance_of(self): engine = test_engine(has_snapshot=True) block = test_block(0) # set or we won't pass the native deploy call engine.snapshot.persisting_block = block gas = contracts.GasToken() neo = contracts.NeoToken() deploy_expected_gas = 30_000_000 deploy_expected_neo = 100_000_000 self.assertEqual( deploy_expected_gas, gas.balance_of(engine.snapshot, self.validator_account) / gas.factor) self.assertEqual( deploy_expected_neo, neo.balance_of(engine.snapshot, self.validator_account)) self.assertEqual(vm.BigInteger.zero(), gas.balance_of(engine.snapshot, types.UInt160.zero())) self.assertEqual(vm.BigInteger.zero(), neo.balance_of(engine.snapshot, types.UInt160.zero()))
def test_native_contract(contract_hash: types.UInt160, operation: str, args=None): engine = test_engine(has_snapshot=True) block = test_block(0) # or we won't pass the native deploy call engine.snapshot.persisting_block = block sb = vm.ScriptBuilder() sb.emit_dynamic_call(contract_hash, operation) script = vm.Script(sb.to_array()) engine.load_script(script) # storing the current script in a contract otherwise "System.Contract.Call" will fail its checks nef = contracts.NEF(script=sb.to_array()) manifest = contracts.ContractManifest("test_contract") next_id = contracts.ManagementContract().get_next_available_id( engine.snapshot) contract = contracts.ContractState(next_id + 1, nef, manifest, 0, to_script_hash(nef.script)) engine.snapshot.contracts.put(contract) return engine
def test_on_persist(self): """ OnPersist will do the following * burn the system and network fees for all transactions * mint the sum of network_fees for all transactions to the address of the consensus node that acted as primary speaker for the block """ engine = test_engine(has_snapshot=True) block = test_block(0) # set or we won't pass the native deploy call engine.snapshot.persisting_block = block gas = contracts.GasToken() # update the TX signer account to point to our validator or the token burn() (part of on persist) # will fail because it can't find an account with balance mock_signer = mock.MagicMock() mock_signer.account = self.validator_account engine.snapshot.persisting_block.transactions[0].signers = [ mock_signer ] # our consensus_data is not setup in a realistic way, so we have to correct for that here # or we fail to get the account of primary consensus node engine.snapshot.persisting_block.header.primary_index = settings.network.validators_count - 1 gas.on_persist(engine) """ Drop the below in a test in UT_NativeContract.cs and change ProtocolSettings.cs to * have a ValidatorsCount of 1 * and the StandbyCommittee should be: 02158c4a4810fa2a6a12f7d33d835680429e1a68ae61161c5b3fbc98c7f1f17765 var snapshot = Blockchain.Singleton.GetSnapshot(); snapshot.PersistingBlock = new Block() { Index = 1000 }; var point = ECPoint.Parse("02158c4a4810fa2a6a12f7d33d835680429e1a68ae61161c5b3fbc98c7f1f17765", ECCurve.Secp256r1); var account = Contract.CreateMultiSigRedeemScript(1, new ECPoint[] {point}).ToScriptHash(); var tx = TestUtils.GetTransaction(account); tx.SystemFee = 456; tx.NetworkFee = 789; snapshot.PersistingBlock.Transactions = new Transaction[] {tx}; snapshot.PersistingBlock.ConsensusData = new ConsensusData { PrimaryIndex = 0}; ApplicationEngine engine2 = ApplicationEngine.Create(TriggerType.System, tx, snapshot, 0); NativeContract.GAS.OnPersist(engine2); var key = new byte[] {0x14}; var sk = key.Concat(account.ToArray()); var item = engine2.Snapshot.Storages.TryGet(new StorageKey {Id = NativeContract.GAS.Id, Key = sk.ToArray()}); var state = item.GetInteroperable<AccountState>(); Console.WriteLine($"account state {state.Balance}"); var item2 = engine2.Snapshot.Storages.TryGet(new StorageKey {Id = NativeContract.GAS.Id, Key = new byte[]{11}}); Console.WriteLine($"total supply {(BigInteger)item2}"); var primary_account = Contract.CreateSignatureRedeemScript(point).ToScriptHash(); var primary_sk = key.Concat(primary_account.ToArray()); var primary_item = engine2.Snapshot.Storages.TryGet(new StorageKey {Id = NativeContract.GAS.Id, Key = primary_sk.ToArray()}); var primary_state = primary_item.GetInteroperable<AccountState>(); Console.WriteLine($"primary account state {primary_state.Balance}"); """ # * our validator prior to on_persist had a balance of 30_000_000 # * after it should have been reduced by the network + system_fee's paid in the transaction sk_gas_supply = gas.key_account + self.validator_account si_supply = engine.snapshot.storages.try_get(sk_gas_supply) self.assertIsNotNone(si_supply) token_state = gas._state.deserialize_from_bytes(si_supply.value) total_fees = engine.snapshot.persisting_block.transactions[0].network_fee + \ engine.snapshot.persisting_block.transactions[0].system_fee expected = (30_000_000 * gas.factor) - total_fees self.assertEqual(expected, int(token_state.balance)) # * total GAS supply was 30_000_000 + 0.5 for committee reward, should be reduced by the system_fee sk_total_supply = gas.key_total_supply si_total_supply = engine.snapshot.storages.try_get(sk_total_supply) self.assertIsNotNone(si_total_supply) committee_reward = vm.BigInteger(50000000) expected = ( (30_000_000 * gas.factor) + committee_reward ) - engine.snapshot.persisting_block.transactions[0].system_fee self.assertEqual(expected, vm.BigInteger(si_total_supply.value)) # * the persisting block contains exactly 1 transaction # * after on_persist the account our primary validator should have been credited with the transaction's # network_fee primary_validator = to_script_hash( contracts.Contract.create_signature_redeemscript( self.validator_public_key)) sk_gas_supply = gas.key_account + primary_validator si_supply = engine.snapshot.storages.try_get(sk_gas_supply) self.assertIsNotNone(si_supply) token_state = gas._state.deserialize_from_bytes(si_supply.value) expected = engine.snapshot.persisting_block.transactions[ 0].network_fee + committee_reward self.assertEqual(expected, int(token_state.balance))