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