123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- package runtime
- import (
- "fmt"
- "math/big"
- "os"
- "strings"
- "testing"
- "github.com/ethereum/go-ethereum/accounts/abi"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/hexutil"
- "github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/rawdb"
- "github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/private/engine"
- testifyassert "github.com/stretchr/testify/assert"
- )
- /*
- The following contracts are used as the samples. Bytecodes are compiled using solc 0.5.4
- import "./C2.sol";
- contract C1 {
- uint x;
- constructor(uint initVal) public {
- x = initVal;
- }
- function set(uint newValue) public returns (uint) {
- x = newValue;
- return x;
- }
- function get() public view returns (uint) {
- return x;
- }
- function newContractC2(uint newValue) public {
- C2 c = new C2(address(this));
- c.set(newValue);
- }
- }
- import "./C1.sol";
- contract C2 {
- C1 c1;
- constructor(address _t) public {
- c1 = C1(_t);
- }
- function get() public view returns (uint result) {
- return c1.get();
- }
- function set(uint _val) public {
- c1.set(_val);
- }
- }
- */
- type contract struct {
- abi abi.ABI
- bytecode []byte
- name string
- }
- var (
- c1, c2 *contract
- stubPrivateTx *types.Transaction
- )
- func init() {
- c1 = &contract{
- name: "c1",
- abi: mustParse(c1AbiDefinition),
- bytecode: common.Hex2Bytes("608060405234801561001057600080fd5b506040516020806105a88339810180604052602081101561003057600080fd5b81019080805190602001909291905050508060008190555050610550806100586000396000f3fe608060405260043610610051576000357c01000000000000000000000000000000000000000000000000000000009004806360fe47b1146100565780636d4ce63c146100a5578063d7139463146100d0575b600080fd5b34801561006257600080fd5b5061008f6004803603602081101561007957600080fd5b810190808035906020019092919050505061010b565b6040518082815260200191505060405180910390f35b3480156100b157600080fd5b506100ba61011e565b6040518082815260200191505060405180910390f35b3480156100dc57600080fd5b50610109600480360360208110156100f357600080fd5b8101908080359060200190929190505050610127565b005b6000816000819055506000549050919050565b60008054905090565b600030610132610212565b808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050604051809103906000f080158015610184573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff166360fe47b1836040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1580156101f657600080fd5b505af115801561020a573d6000803e3d6000fd5b505050505050565b604051610302806102238339019056fe608060405234801561001057600080fd5b506040516020806103028339810180604052602081101561003057600080fd5b8101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610271806100916000396000f3fe608060405260043610610046576000357c01000000000000000000000000000000000000000000000000000000009004806360fe47b11461004b5780636d4ce63c14610086575b600080fd5b34801561005757600080fd5b506100846004803603602081101561006e57600080fd5b81019080803590602001909291905050506100b1565b005b34801561009257600080fd5b5061009b610180565b6040518082815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166360fe47b1826040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b15801561014157600080fd5b505af1158015610155573d6000803e3d6000fd5b505050506040513d602081101561016b57600080fd5b81019080805190602001909291905050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636d4ce63c6040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b15801561020557600080fd5b505afa158015610219573d6000803e3d6000fd5b505050506040513d602081101561022f57600080fd5b810190808051906020019092919050505090509056fea165627a7a72305820a537f4c360ce5c6f55523298e314e6456e5c3e02c170563751dfda37d3aeddb30029a165627a7a7230582060396bfff29d2dfc5a9f4216bfba5e24d031d54fd4b26ebebde1a26c59df0c1e0029"),
- }
- c2 = &contract{
- name: "c2",
- abi: mustParse(c2AbiDefinition),
- bytecode: common.Hex2Bytes("608060405234801561001057600080fd5b506040516020806102f58339810180604052602081101561003057600080fd5b8101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610264806100916000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c01000000000000000000000000000000000000000000000000000000009004806360fe47b1146100585780636d4ce63c14610086575b600080fd5b6100846004803603602081101561006e57600080fd5b81019080803590602001909291905050506100a4565b005b61008e610173565b6040518082815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166360fe47b1826040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b15801561013457600080fd5b505af1158015610148573d6000803e3d6000fd5b505050506040513d602081101561015e57600080fd5b81019080805190602001909291905050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636d4ce63c6040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b1580156101f857600080fd5b505afa15801561020c573d6000803e3d6000fd5b505050506040513d602081101561022257600080fd5b810190808051906020019092919050505090509056fea165627a7a72305820dd8a5dcf693e1969289c444a282d0684a9760bac26f1e4e0139d46821ec1979b0029"),
- }
- log.PrintOrigins(true)
- log.Root().SetHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(true)))
- }
- func TestPrivacyEnhancements_CreateC1(t *testing.T) {
- assert := testifyassert.New(t)
- cfg := newConfig()
- initialValue := int64(42)
- var affectedContracts []common.Address
- var getPrivacyMetadataFunc func(common.Address) (*state.PrivacyMetadata, error)
- cfg.onAfterEVM = func(evm *vm.EVM) {
- affectedContracts = evm.AffectedContracts()
- getPrivacyMetadataFunc = evm.StateDB.GetPrivacyMetadata
- }
- stubPrivateTx = newTypicalPrivateTx(cfg)
- stubPrivateTx.SetTxPrivacyMetadata(&types.PrivacyMetadata{
- PrivacyFlag: engine.PrivacyFlagStateValidation,
- })
- c1Address := createC1(assert, cfg, initialValue)
- assert.Empty(affectedContracts, "Contract C1 creation doesn't affect any other contract")
- pm, err := getPrivacyMetadataFunc(c1Address)
- assert.NoError(err, "Privacy Metadata must exist")
- assert.True(pm.PrivacyFlag.Has(engine.PrivacyFlagStateValidation), "PrivacyFlag must be set")
- assert.Equal(common.BytesToEncryptedPayloadHash(stubPrivateTx.Data()), pm.CreationTxHash, "CreationTxHash must be set correctly")
- actualValue := callContractFunction(assert, cfg, c1, c1Address, "get")
- assert.Equal(initialValue, actualValue)
- assert.Len(affectedContracts, 1, "Calling C1.get() affects 1 contract")
- assert.Equal(c1Address, affectedContracts[0], "Calling C1.get() affects C1 contract itself")
- }
- func TestPrivacyEnhancements_CreateC2(t *testing.T) {
- assert := testifyassert.New(t)
- cfg := newConfig()
- stubPrivateTx = nil
- initialValue := int64(30)
- c1Address := createC1(assert, cfg, initialValue)
- var affectedContracts []common.Address
- cfg.onAfterEVM = func(evm *vm.EVM) {
- affectedContracts = evm.AffectedContracts()
- }
- c2Address := createC2(assert, cfg, c1Address)
- assert.Empty(affectedContracts, "Contract C2 creation doesn't affect any other contract")
- actualValue := callContractFunction(assert, cfg, c2, c2Address, "get")
- assert.Equal(initialValue, actualValue)
- assert.Len(affectedContracts, 2, "Calling C2.get() affects 2 contracts")
- assert.Contains(affectedContracts, c1Address, "Calling C2.get() affects C1")
- assert.Contains(affectedContracts, c2Address, "Calling C2.get() affects C2")
- }
- func TestPrivacyEnhancements_CreateC2FromC1Function(t *testing.T) {
- assert := testifyassert.New(t)
- cfg := newConfig()
- stubPrivateTx = nil
- initialValue := int64(30)
- newValue := int64(40)
- c1Address := createC1(assert, cfg, initialValue)
- var affectedContracts []common.Address
- cfg.onAfterEVM = func(evm *vm.EVM) {
- affectedContracts = evm.AffectedContracts()
- }
- callContractFunction(assert, cfg, c1, c1Address, "newContractC2", big.NewInt(newValue))
- assert.Len(affectedContracts, 1, "Calling C1.newContractC2() affects 1 contract")
- assert.Contains(affectedContracts, c1Address, "Calling C1.newContractC2() affects C1")
- }
- func TestPrivacyEnhancements_CreateC1_StandardPrivate(t *testing.T) {
- assert := testifyassert.New(t)
- cfg := newConfig()
- initialValue := int64(42)
- var affectedContracts []common.Address
- var getPrivacyMetadataFunc func(common.Address) (*state.PrivacyMetadata, error)
- cfg.onAfterEVM = func(evm *vm.EVM) {
- affectedContracts = evm.AffectedContracts()
- getPrivacyMetadataFunc = evm.StateDB.GetPrivacyMetadata
- }
- stubPrivateTx = newTypicalPrivateTx(cfg)
- stubPrivateTx.SetTxPrivacyMetadata(&types.PrivacyMetadata{
- PrivacyFlag: engine.PrivacyFlagStandardPrivate,
- })
- c1Address := createC1(assert, cfg, initialValue)
- assert.Empty(affectedContracts, "Contract C1 creation doesn't affect any other contract")
- _, err := getPrivacyMetadataFunc(c1Address)
- assert.Error(err, "Privacy Metadata must not exist")
- actualValue := callContractFunction(assert, cfg, c1, c1Address, "get")
- assert.Equal(initialValue, actualValue)
- assert.Len(affectedContracts, 1, "Calling C1.get() affects 1 contract")
- assert.Equal(c1Address, affectedContracts[0], "Calling C1.get() affects C1 contract itself")
- }
- func callContractFunction(assert *testifyassert.Assertions, cfg *extendedConfig, c *contract, address common.Address, name string, args ...interface{}) int64 {
- f := mustPack(assert, c, name, args...)
- ret, _, err := call(address, f, cfg)
- sig := fmt.Sprintf("%s.%s", c.name, name)
- assert.NoError(err, "Execute %s", sig)
- log.Debug(sig, "ret_hex", common.Bytes2Hex(ret))
- for len(ret) > 0 && ret[0] == 0 {
- ret = ret[1:]
- }
- if len(ret) == 0 {
- return -1
- }
- actualValue, err := hexutil.DecodeBig(hexutil.Encode(ret))
- assert.NoError(err)
- log.Debug(sig, "ret", actualValue)
- return actualValue.Int64()
- }
- func createC2(assert *testifyassert.Assertions, cfg *extendedConfig, c1Address common.Address) common.Address {
- constructorCode := mustPack(assert, c2, "", c1Address)
- _, address, _, err := create(append(c2.bytecode, constructorCode...), cfg)
- assert.NoError(err, "Create contract C2")
- log.Debug("Created C2", "address", address.Hex())
- return address
- }
- func createC1(assert *testifyassert.Assertions, cfg *extendedConfig, initialValue int64) common.Address {
- constructorCode := mustPack(assert, c1, "", big.NewInt(initialValue))
- _, address, _, err := create(append(c1.bytecode, constructorCode...), cfg)
- assert.NoError(err, "Create contract C1")
- log.Debug("Created C1", "address", address.Hex())
- return address
- }
- func mustPack(assert *testifyassert.Assertions, c *contract, name string, args ...interface{}) []byte {
- bytes, err := c.abi.Pack(name, args...)
- assert.NoError(err, "Pack method")
- return bytes
- }
- func newConfig() *extendedConfig {
- cfg := new(Config)
- setDefaults(cfg)
- cfg.Debug = true
- database := rawdb.NewMemoryDatabase()
- cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(database), nil)
- privateState, _ := state.New(common.Hash{}, state.NewDatabase(database), nil)
- cfg.ChainConfig.IsQuorum = true
- cfg.ChainConfig.ByzantiumBlock = big.NewInt(0)
- return &extendedConfig{
- Config: cfg,
- privateState: privateState,
- }
- }
- type extendedConfig struct {
- *Config
- privateState *state.StateDB
- onAfterEVM func(evm *vm.EVM)
- }
- func newEVM(cfg *extendedConfig) *vm.EVM {
- context := vm.BlockContext{
- CanTransfer: core.CanTransfer,
- Transfer: core.Transfer,
- GetHash: func(uint64) common.Hash { return common.Hash{} },
- Coinbase: cfg.Coinbase,
- BlockNumber: cfg.BlockNumber,
- Time: cfg.Time,
- Difficulty: cfg.Difficulty,
- GasLimit: cfg.GasLimit,
- }
- txContext := vm.TxContext{
- Origin: cfg.Origin,
- GasPrice: cfg.GasPrice,
- }
- evm := vm.NewEVM(context, txContext, cfg.State, cfg.privateState, cfg.ChainConfig, cfg.EVMConfig)
- evm.SetCurrentTX(stubPrivateTx)
- return evm
- }
- func newTypicalPrivateTx(cfg *extendedConfig) *types.Transaction {
- tx := types.NewTransaction(0, common.Address{}, cfg.Value, cfg.GasLimit, cfg.GasPrice, []byte("arbitrary payload"))
- tx.SetPrivate()
- return tx
- }
- // Create executes the code using the EVM create method
- func create(input []byte, cfg *extendedConfig) ([]byte, common.Address, uint64, error) {
- var (
- vmenv = newEVM(cfg)
- sender = vm.AccountRef(cfg.Origin)
- )
- defer func() {
- if cfg.onAfterEVM != nil {
- cfg.onAfterEVM(vmenv)
- }
- }()
- // Call the code with the given configuration.
- code, address, leftOverGas, err := vmenv.Create(
- sender,
- input,
- cfg.GasLimit,
- cfg.Value,
- )
- return code, address, leftOverGas, err
- }
- // Call executes the code given by the contract's address. It will return the
- // EVM's return value or an error if it failed.
- //
- // Call, unlike Execute, requires a config and also requires the State field to
- // be set.
- func call(address common.Address, input []byte, cfg *extendedConfig) ([]byte, uint64, error) {
- vmenv := newEVM(cfg)
- defer func() {
- if cfg.onAfterEVM != nil {
- cfg.onAfterEVM(vmenv)
- }
- }()
- sender := cfg.State.GetOrNewStateObject(cfg.Origin)
- // Call the code with the given configuration.
- ret, leftOverGas, err := vmenv.Call(
- sender,
- address,
- input,
- cfg.GasLimit,
- cfg.Value,
- )
- return ret, leftOverGas, err
- }
- func mustParse(def string) abi.ABI {
- abi, err := abi.JSON(strings.NewReader(def))
- if err != nil {
- log.Error("Can't parse ABI def", "err", err)
- os.Exit(1)
- }
- return abi
- }
- const (
- c1AbiDefinition = `
- [
- {
- "constant": false,
- "inputs": [
- {
- "name": "newValue",
- "type": "uint256"
- }
- ],
- "name": "set",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [],
- "name": "get",
- "outputs": [
- {
- "name": "",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "constant": false,
- "inputs": [
- {
- "name": "newValue",
- "type": "uint256"
- }
- ],
- "name": "newContractC2",
- "outputs": [],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "inputs": [
- {
- "name": "initVal",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "constructor"
- }
- ]
- `
- c2AbiDefinition = `
- [
- {
- "constant": false,
- "inputs": [
- {
- "name": "_val",
- "type": "uint256"
- }
- ],
- "name": "set",
- "outputs": [],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "function"
- },
- {
- "constant": true,
- "inputs": [],
- "name": "get",
- "outputs": [
- {
- "name": "result",
- "type": "uint256"
- }
- ],
- "payable": false,
- "stateMutability": "view",
- "type": "function"
- },
- {
- "inputs": [
- {
- "name": "_t",
- "type": "address"
- }
- ],
- "payable": false,
- "stateMutability": "nonpayable",
- "type": "constructor"
- }
- ]
- `
- )
|