github.com/corverroos/quorum@v21.1.0+incompatible/core/vm/runtime/evm_privacy_test.go (about)

     1  package runtime
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  	"os"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/ethereum/go-ethereum/accounts/abi"
    11  	"github.com/ethereum/go-ethereum/common"
    12  	"github.com/ethereum/go-ethereum/common/hexutil"
    13  	"github.com/ethereum/go-ethereum/core"
    14  	"github.com/ethereum/go-ethereum/core/rawdb"
    15  	"github.com/ethereum/go-ethereum/core/state"
    16  	"github.com/ethereum/go-ethereum/core/types"
    17  	"github.com/ethereum/go-ethereum/core/vm"
    18  	"github.com/ethereum/go-ethereum/log"
    19  	"github.com/ethereum/go-ethereum/private/engine"
    20  	testifyassert "github.com/stretchr/testify/assert"
    21  )
    22  
    23  /*
    24  The following contracts are used as the samples. Bytecodes are compiled using solc 0.5.4
    25  
    26  import "./C2.sol";
    27  
    28  contract C1 {
    29  
    30      uint x;
    31  
    32      constructor(uint initVal) public {
    33          x = initVal;
    34      }
    35  
    36      function set(uint newValue) public returns (uint) {
    37          x = newValue;
    38          return x;
    39      }
    40  
    41      function get() public view returns (uint) {
    42          return x;
    43      }
    44  
    45      function newContractC2(uint newValue) public {
    46          C2 c = new C2(address(this));
    47          c.set(newValue);
    48      }
    49  }
    50  
    51  import "./C1.sol";
    52  
    53  contract C2  {
    54  
    55     C1 c1;
    56  
    57     constructor(address _t) public {
    58         c1 = C1(_t);
    59     }
    60  
    61     function get() public view returns (uint result) {
    62         return c1.get();
    63     }
    64  
    65     function set(uint _val) public {
    66         c1.set(_val);
    67     }
    68  
    69  }
    70  */
    71  
    72  type contract struct {
    73  	abi      abi.ABI
    74  	bytecode []byte
    75  	name     string
    76  }
    77  
    78  var (
    79  	c1, c2        *contract
    80  	stubPrivateTx *types.Transaction
    81  )
    82  
    83  func init() {
    84  	c1 = &contract{
    85  		name:     "c1",
    86  		abi:      mustParse(c1AbiDefinition),
    87  		bytecode: common.Hex2Bytes("608060405234801561001057600080fd5b506040516020806105a88339810180604052602081101561003057600080fd5b81019080805190602001909291905050508060008190555050610550806100586000396000f3fe608060405260043610610051576000357c01000000000000000000000000000000000000000000000000000000009004806360fe47b1146100565780636d4ce63c146100a5578063d7139463146100d0575b600080fd5b34801561006257600080fd5b5061008f6004803603602081101561007957600080fd5b810190808035906020019092919050505061010b565b6040518082815260200191505060405180910390f35b3480156100b157600080fd5b506100ba61011e565b6040518082815260200191505060405180910390f35b3480156100dc57600080fd5b50610109600480360360208110156100f357600080fd5b8101908080359060200190929190505050610127565b005b6000816000819055506000549050919050565b60008054905090565b600030610132610212565b808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050604051809103906000f080158015610184573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff166360fe47b1836040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b1580156101f657600080fd5b505af115801561020a573d6000803e3d6000fd5b505050505050565b604051610302806102238339019056fe608060405234801561001057600080fd5b506040516020806103028339810180604052602081101561003057600080fd5b8101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610271806100916000396000f3fe608060405260043610610046576000357c01000000000000000000000000000000000000000000000000000000009004806360fe47b11461004b5780636d4ce63c14610086575b600080fd5b34801561005757600080fd5b506100846004803603602081101561006e57600080fd5b81019080803590602001909291905050506100b1565b005b34801561009257600080fd5b5061009b610180565b6040518082815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166360fe47b1826040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b15801561014157600080fd5b505af1158015610155573d6000803e3d6000fd5b505050506040513d602081101561016b57600080fd5b81019080805190602001909291905050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636d4ce63c6040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b15801561020557600080fd5b505afa158015610219573d6000803e3d6000fd5b505050506040513d602081101561022f57600080fd5b810190808051906020019092919050505090509056fea165627a7a72305820a537f4c360ce5c6f55523298e314e6456e5c3e02c170563751dfda37d3aeddb30029a165627a7a7230582060396bfff29d2dfc5a9f4216bfba5e24d031d54fd4b26ebebde1a26c59df0c1e0029"),
    88  	}
    89  	c2 = &contract{
    90  		name:     "c2",
    91  		abi:      mustParse(c2AbiDefinition),
    92  		bytecode: common.Hex2Bytes("608060405234801561001057600080fd5b506040516020806102f58339810180604052602081101561003057600080fd5b8101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610264806100916000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c01000000000000000000000000000000000000000000000000000000009004806360fe47b1146100585780636d4ce63c14610086575b600080fd5b6100846004803603602081101561006e57600080fd5b81019080803590602001909291905050506100a4565b005b61008e610173565b6040518082815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166360fe47b1826040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050602060405180830381600087803b15801561013457600080fd5b505af1158015610148573d6000803e3d6000fd5b505050506040513d602081101561015e57600080fd5b81019080805190602001909291905050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636d4ce63c6040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b1580156101f857600080fd5b505afa15801561020c573d6000803e3d6000fd5b505050506040513d602081101561022257600080fd5b810190808051906020019092919050505090509056fea165627a7a72305820dd8a5dcf693e1969289c444a282d0684a9760bac26f1e4e0139d46821ec1979b0029"),
    93  	}
    94  	log.PrintOrigins(true)
    95  	log.Root().SetHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(true)))
    96  }
    97  
    98  func TestPrivacyEnhancements_CreateC1(t *testing.T) {
    99  	assert := testifyassert.New(t)
   100  	cfg := newConfig()
   101  	initialValue := int64(42)
   102  	var affectedContracts []common.Address
   103  	var getPrivacyMetadataFunc func(common.Address) (*state.PrivacyMetadata, error)
   104  	cfg.onAfterEVM = func(evm *vm.EVM) {
   105  		affectedContracts = evm.AffectedContracts()
   106  		getPrivacyMetadataFunc = evm.StateDB.GetPrivacyMetadata
   107  	}
   108  	stubPrivateTx = newTypicalPrivateTx(cfg)
   109  	stubPrivateTx.SetTxPrivacyMetadata(&types.PrivacyMetadata{
   110  		PrivacyFlag: engine.PrivacyFlagStateValidation,
   111  	})
   112  
   113  	c1Address := createC1(assert, cfg, initialValue)
   114  	assert.Empty(affectedContracts, "Contract C1 creation doesn't affect any other contract")
   115  	pm, err := getPrivacyMetadataFunc(c1Address)
   116  	assert.NoError(err, "Privacy Metadata must exist")
   117  	assert.True(pm.PrivacyFlag.Has(engine.PrivacyFlagStateValidation), "PrivacyFlag must be set")
   118  	assert.Equal(common.BytesToEncryptedPayloadHash(stubPrivateTx.Data()), pm.CreationTxHash, "CreationTxHash must be set correctly")
   119  
   120  	actualValue := callContractFunction(assert, cfg, c1, c1Address, "get")
   121  	assert.Equal(initialValue, actualValue)
   122  	assert.Len(affectedContracts, 1, "Calling C1.get() affects 1 contract")
   123  	assert.Equal(c1Address, affectedContracts[0], "Calling C1.get() affects C1 contract itself")
   124  }
   125  
   126  func TestPrivacyEnhancements_CreateC2(t *testing.T) {
   127  	assert := testifyassert.New(t)
   128  	cfg := newConfig()
   129  	stubPrivateTx = nil
   130  	initialValue := int64(30)
   131  
   132  	c1Address := createC1(assert, cfg, initialValue)
   133  
   134  	var affectedContracts []common.Address
   135  	cfg.onAfterEVM = func(evm *vm.EVM) {
   136  		affectedContracts = evm.AffectedContracts()
   137  	}
   138  	c2Address := createC2(assert, cfg, c1Address)
   139  	assert.Empty(affectedContracts, "Contract C2 creation doesn't affect any other contract")
   140  
   141  	actualValue := callContractFunction(assert, cfg, c2, c2Address, "get")
   142  
   143  	assert.Equal(initialValue, actualValue)
   144  	assert.Len(affectedContracts, 2, "Calling C2.get() affects 2 contracts")
   145  	assert.Contains(affectedContracts, c1Address, "Calling C2.get() affects C1")
   146  	assert.Contains(affectedContracts, c2Address, "Calling C2.get() affects C2")
   147  }
   148  
   149  func TestPrivacyEnhancements_CreateC2FromC1Function(t *testing.T) {
   150  	assert := testifyassert.New(t)
   151  	cfg := newConfig()
   152  	stubPrivateTx = nil
   153  	initialValue := int64(30)
   154  	newValue := int64(40)
   155  
   156  	c1Address := createC1(assert, cfg, initialValue)
   157  
   158  	var affectedContracts []common.Address
   159  	cfg.onAfterEVM = func(evm *vm.EVM) {
   160  		affectedContracts = evm.AffectedContracts()
   161  	}
   162  	callContractFunction(assert, cfg, c1, c1Address, "newContractC2", big.NewInt(newValue))
   163  
   164  	assert.Len(affectedContracts, 1, "Calling C1.newContractC2() affects 1 contract")
   165  	assert.Contains(affectedContracts, c1Address, "Calling C1.newContractC2() affects C1")
   166  }
   167  
   168  func TestPrivacyEnhancements_CreateC1_StandardPrivate(t *testing.T) {
   169  	assert := testifyassert.New(t)
   170  	cfg := newConfig()
   171  	initialValue := int64(42)
   172  	var affectedContracts []common.Address
   173  	var getPrivacyMetadataFunc func(common.Address) (*state.PrivacyMetadata, error)
   174  	cfg.onAfterEVM = func(evm *vm.EVM) {
   175  		affectedContracts = evm.AffectedContracts()
   176  		getPrivacyMetadataFunc = evm.StateDB.GetPrivacyMetadata
   177  	}
   178  	stubPrivateTx = newTypicalPrivateTx(cfg)
   179  	stubPrivateTx.SetTxPrivacyMetadata(&types.PrivacyMetadata{
   180  		PrivacyFlag: engine.PrivacyFlagStandardPrivate,
   181  	})
   182  
   183  	c1Address := createC1(assert, cfg, initialValue)
   184  	assert.Empty(affectedContracts, "Contract C1 creation doesn't affect any other contract")
   185  	_, err := getPrivacyMetadataFunc(c1Address)
   186  	assert.Error(err, "Privacy Metadata must not exist")
   187  
   188  	actualValue := callContractFunction(assert, cfg, c1, c1Address, "get")
   189  	assert.Equal(initialValue, actualValue)
   190  	assert.Len(affectedContracts, 1, "Calling C1.get() affects 1 contract")
   191  	assert.Equal(c1Address, affectedContracts[0], "Calling C1.get() affects C1 contract itself")
   192  }
   193  
   194  func callContractFunction(assert *testifyassert.Assertions, cfg *extendedConfig, c *contract, address common.Address, name string, args ...interface{}) int64 {
   195  	f := mustPack(assert, c, name, args...)
   196  	ret, _, err := call(address, f, cfg)
   197  	sig := fmt.Sprintf("%s.%s", c.name, name)
   198  	assert.NoError(err, "Execute %s", sig)
   199  	log.Debug(sig, "ret_hex", common.Bytes2Hex(ret))
   200  	for len(ret) > 0 && ret[0] == 0 {
   201  		ret = ret[1:]
   202  	}
   203  	if len(ret) == 0 {
   204  		return -1
   205  	}
   206  	actualValue, err := hexutil.DecodeBig(hexutil.Encode(ret))
   207  	assert.NoError(err)
   208  	log.Debug(sig, "ret", actualValue)
   209  	return actualValue.Int64()
   210  }
   211  
   212  func createC2(assert *testifyassert.Assertions, cfg *extendedConfig, c1Address common.Address) common.Address {
   213  	constructorCode := mustPack(assert, c2, "", c1Address)
   214  
   215  	_, address, _, err := create(append(c2.bytecode, constructorCode...), cfg)
   216  	assert.NoError(err, "Create contract C2")
   217  
   218  	log.Debug("Created C2", "address", address.Hex())
   219  	return address
   220  }
   221  
   222  func createC1(assert *testifyassert.Assertions, cfg *extendedConfig, initialValue int64) common.Address {
   223  	constructorCode := mustPack(assert, c1, "", big.NewInt(initialValue))
   224  
   225  	_, address, _, err := create(append(c1.bytecode, constructorCode...), cfg)
   226  	assert.NoError(err, "Create contract C1")
   227  
   228  	log.Debug("Created C1", "address", address.Hex())
   229  	return address
   230  }
   231  
   232  func mustPack(assert *testifyassert.Assertions, c *contract, name string, args ...interface{}) []byte {
   233  	bytes, err := c.abi.Pack(name, args...)
   234  	assert.NoError(err, "Pack method")
   235  	return bytes
   236  }
   237  
   238  func newConfig() *extendedConfig {
   239  	cfg := new(Config)
   240  	setDefaults(cfg)
   241  	cfg.Debug = true
   242  	database := rawdb.NewMemoryDatabase()
   243  	cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(database))
   244  	privateState, _ := state.New(common.Hash{}, state.NewDatabase(database))
   245  
   246  	cfg.ChainConfig.IsQuorum = true
   247  	cfg.ChainConfig.ByzantiumBlock = big.NewInt(0)
   248  	return &extendedConfig{
   249  		Config:       cfg,
   250  		privateState: privateState,
   251  	}
   252  }
   253  
   254  type extendedConfig struct {
   255  	*Config
   256  	privateState *state.StateDB
   257  	onAfterEVM   func(evm *vm.EVM)
   258  }
   259  
   260  func newEVM(cfg *extendedConfig) *vm.EVM {
   261  	context := vm.Context{
   262  		CanTransfer: core.CanTransfer,
   263  		Transfer:    core.Transfer,
   264  		GetHash:     func(uint64) common.Hash { return common.Hash{} },
   265  
   266  		Origin:      cfg.Origin,
   267  		Coinbase:    cfg.Coinbase,
   268  		BlockNumber: cfg.BlockNumber,
   269  		Time:        cfg.Time,
   270  		Difficulty:  cfg.Difficulty,
   271  		GasLimit:    cfg.GasLimit,
   272  		GasPrice:    cfg.GasPrice,
   273  	}
   274  	evm := vm.NewEVM(context, cfg.State, cfg.privateState, cfg.ChainConfig, cfg.EVMConfig)
   275  	evm.SetCurrentTX(stubPrivateTx)
   276  	return evm
   277  }
   278  
   279  func newTypicalPrivateTx(cfg *extendedConfig) *types.Transaction {
   280  	tx := types.NewTransaction(0, common.Address{}, cfg.Value, cfg.GasLimit, cfg.GasPrice, []byte("arbitrary payload"))
   281  	tx.SetPrivate()
   282  	return tx
   283  }
   284  
   285  // Create executes the code using the EVM create method
   286  func create(input []byte, cfg *extendedConfig) ([]byte, common.Address, uint64, error) {
   287  	var (
   288  		vmenv  = newEVM(cfg)
   289  		sender = vm.AccountRef(cfg.Origin)
   290  	)
   291  	defer func() {
   292  		if cfg.onAfterEVM != nil {
   293  			cfg.onAfterEVM(vmenv)
   294  		}
   295  	}()
   296  
   297  	// Call the code with the given configuration.
   298  	code, address, leftOverGas, err := vmenv.Create(
   299  		sender,
   300  		input,
   301  		cfg.GasLimit,
   302  		cfg.Value,
   303  	)
   304  	return code, address, leftOverGas, err
   305  }
   306  
   307  // Call executes the code given by the contract's address. It will return the
   308  // EVM's return value or an error if it failed.
   309  //
   310  // Call, unlike Execute, requires a config and also requires the State field to
   311  // be set.
   312  func call(address common.Address, input []byte, cfg *extendedConfig) ([]byte, uint64, error) {
   313  	vmenv := newEVM(cfg)
   314  	defer func() {
   315  		if cfg.onAfterEVM != nil {
   316  			cfg.onAfterEVM(vmenv)
   317  		}
   318  	}()
   319  
   320  	sender := cfg.State.GetOrNewStateObject(cfg.Origin)
   321  	// Call the code with the given configuration.
   322  	ret, leftOverGas, err := vmenv.Call(
   323  		sender,
   324  		address,
   325  		input,
   326  		cfg.GasLimit,
   327  		cfg.Value,
   328  	)
   329  
   330  	return ret, leftOverGas, err
   331  }
   332  
   333  func mustParse(def string) abi.ABI {
   334  	abi, err := abi.JSON(strings.NewReader(def))
   335  	if err != nil {
   336  		log.Error("Can't parse ABI def", "err", err)
   337  		os.Exit(1)
   338  	}
   339  	return abi
   340  }
   341  
   342  const (
   343  	c1AbiDefinition = `
   344  [
   345  	{
   346  		"constant": false,
   347  		"inputs": [
   348  			{
   349  				"name": "newValue",
   350  				"type": "uint256"
   351  			}
   352  		],
   353  		"name": "set",
   354  		"outputs": [
   355  			{
   356  				"name": "",
   357  				"type": "uint256"
   358  			}
   359  		],
   360  		"payable": false,
   361  		"stateMutability": "nonpayable",
   362  		"type": "function"
   363  	},
   364  	{
   365  		"constant": true,
   366  		"inputs": [],
   367  		"name": "get",
   368  		"outputs": [
   369  			{
   370  				"name": "",
   371  				"type": "uint256"
   372  			}
   373  		],
   374  		"payable": false,
   375  		"stateMutability": "view",
   376  		"type": "function"
   377  	},
   378  	{
   379  		"constant": false,
   380  		"inputs": [
   381  			{
   382  				"name": "newValue",
   383  				"type": "uint256"
   384  			}
   385  		],
   386  		"name": "newContractC2",
   387  		"outputs": [],
   388  		"payable": false,
   389  		"stateMutability": "nonpayable",
   390  		"type": "function"
   391  	},
   392  	{
   393  		"inputs": [
   394  			{
   395  				"name": "initVal",
   396  				"type": "uint256"
   397  			}
   398  		],
   399  		"payable": false,
   400  		"stateMutability": "nonpayable",
   401  		"type": "constructor"
   402  	}
   403  ]
   404  `
   405  	c2AbiDefinition = `
   406  [
   407  	{
   408  		"constant": false,
   409  		"inputs": [
   410  			{
   411  				"name": "_val",
   412  				"type": "uint256"
   413  			}
   414  		],
   415  		"name": "set",
   416  		"outputs": [],
   417  		"payable": false,
   418  		"stateMutability": "nonpayable",
   419  		"type": "function"
   420  	},
   421  	{
   422  		"constant": true,
   423  		"inputs": [],
   424  		"name": "get",
   425  		"outputs": [
   426  			{
   427  				"name": "result",
   428  				"type": "uint256"
   429  			}
   430  		],
   431  		"payable": false,
   432  		"stateMutability": "view",
   433  		"type": "function"
   434  	},
   435  	{
   436  		"inputs": [
   437  			{
   438  				"name": "_t",
   439  				"type": "address"
   440  			}
   441  		],
   442  		"payable": false,
   443  		"stateMutability": "nonpayable",
   444  		"type": "constructor"
   445  	}
   446  ]
   447  `
   448  )