예제 #1
0
    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
예제 #2
0
 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)
예제 #3
0
    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())
예제 #4
0
    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))
예제 #5
0
    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))
예제 #6
0
    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))
예제 #7
0
    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)
예제 #8
0
    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)
예제 #9
0
    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()))
예제 #10
0
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
예제 #11
0
    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))