github.com/baptiste-b-pegasys/quorum/v22@v22.4.2/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), nil)
   244  	privateState, _ := state.New(common.Hash{}, state.NewDatabase(database), nil)
   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.BlockContext{
   262  		CanTransfer: core.CanTransfer,
   263  		Transfer:    core.Transfer,
   264  		GetHash:     func(uint64) common.Hash { return common.Hash{} },
   265  
   266  		Coinbase:    cfg.Coinbase,
   267  		BlockNumber: cfg.BlockNumber,
   268  		Time:        cfg.Time,
   269  		Difficulty:  cfg.Difficulty,
   270  		GasLimit:    cfg.GasLimit,
   271  	}
   272  	txContext := vm.TxContext{
   273  		Origin:   cfg.Origin,
   274  		GasPrice: cfg.GasPrice,
   275  	}
   276  	evm := vm.NewEVM(context, txContext, cfg.State, cfg.privateState, cfg.ChainConfig, cfg.EVMConfig)
   277  	evm.SetCurrentTX(stubPrivateTx)
   278  	return evm
   279  }
   280  
   281  func newTypicalPrivateTx(cfg *extendedConfig) *types.Transaction {
   282  	tx := types.NewTransaction(0, common.Address{}, cfg.Value, cfg.GasLimit, cfg.GasPrice, []byte("arbitrary payload"))
   283  	tx.SetPrivate()
   284  	return tx
   285  }
   286  
   287  // Create executes the code using the EVM create method
   288  func create(input []byte, cfg *extendedConfig) ([]byte, common.Address, uint64, error) {
   289  	var (
   290  		vmenv  = newEVM(cfg)
   291  		sender = vm.AccountRef(cfg.Origin)
   292  	)
   293  	defer func() {
   294  		if cfg.onAfterEVM != nil {
   295  			cfg.onAfterEVM(vmenv)
   296  		}
   297  	}()
   298  
   299  	// Call the code with the given configuration.
   300  	code, address, leftOverGas, err := vmenv.Create(
   301  		sender,
   302  		input,
   303  		cfg.GasLimit,
   304  		cfg.Value,
   305  	)
   306  	return code, address, leftOverGas, err
   307  }
   308  
   309  // Call executes the code given by the contract's address. It will return the
   310  // EVM's return value or an error if it failed.
   311  //
   312  // Call, unlike Execute, requires a config and also requires the State field to
   313  // be set.
   314  func call(address common.Address, input []byte, cfg *extendedConfig) ([]byte, uint64, error) {
   315  	vmenv := newEVM(cfg)
   316  	defer func() {
   317  		if cfg.onAfterEVM != nil {
   318  			cfg.onAfterEVM(vmenv)
   319  		}
   320  	}()
   321  
   322  	sender := cfg.State.GetOrNewStateObject(cfg.Origin)
   323  	// Call the code with the given configuration.
   324  	ret, leftOverGas, err := vmenv.Call(
   325  		sender,
   326  		address,
   327  		input,
   328  		cfg.GasLimit,
   329  		cfg.Value,
   330  	)
   331  
   332  	return ret, leftOverGas, err
   333  }
   334  
   335  func mustParse(def string) abi.ABI {
   336  	abi, err := abi.JSON(strings.NewReader(def))
   337  	if err != nil {
   338  		log.Error("Can't parse ABI def", "err", err)
   339  		os.Exit(1)
   340  	}
   341  	return abi
   342  }
   343  
   344  const (
   345  	c1AbiDefinition = `
   346  [
   347  	{
   348  		"constant": false,
   349  		"inputs": [
   350  			{
   351  				"name": "newValue",
   352  				"type": "uint256"
   353  			}
   354  		],
   355  		"name": "set",
   356  		"outputs": [
   357  			{
   358  				"name": "",
   359  				"type": "uint256"
   360  			}
   361  		],
   362  		"payable": false,
   363  		"stateMutability": "nonpayable",
   364  		"type": "function"
   365  	},
   366  	{
   367  		"constant": true,
   368  		"inputs": [],
   369  		"name": "get",
   370  		"outputs": [
   371  			{
   372  				"name": "",
   373  				"type": "uint256"
   374  			}
   375  		],
   376  		"payable": false,
   377  		"stateMutability": "view",
   378  		"type": "function"
   379  	},
   380  	{
   381  		"constant": false,
   382  		"inputs": [
   383  			{
   384  				"name": "newValue",
   385  				"type": "uint256"
   386  			}
   387  		],
   388  		"name": "newContractC2",
   389  		"outputs": [],
   390  		"payable": false,
   391  		"stateMutability": "nonpayable",
   392  		"type": "function"
   393  	},
   394  	{
   395  		"inputs": [
   396  			{
   397  				"name": "initVal",
   398  				"type": "uint256"
   399  			}
   400  		],
   401  		"payable": false,
   402  		"stateMutability": "nonpayable",
   403  		"type": "constructor"
   404  	}
   405  ]
   406  `
   407  	c2AbiDefinition = `
   408  [
   409  	{
   410  		"constant": false,
   411  		"inputs": [
   412  			{
   413  				"name": "_val",
   414  				"type": "uint256"
   415  			}
   416  		],
   417  		"name": "set",
   418  		"outputs": [],
   419  		"payable": false,
   420  		"stateMutability": "nonpayable",
   421  		"type": "function"
   422  	},
   423  	{
   424  		"constant": true,
   425  		"inputs": [],
   426  		"name": "get",
   427  		"outputs": [
   428  			{
   429  				"name": "result",
   430  				"type": "uint256"
   431  			}
   432  		],
   433  		"payable": false,
   434  		"stateMutability": "view",
   435  		"type": "function"
   436  	},
   437  	{
   438  		"inputs": [
   439  			{
   440  				"name": "_t",
   441  				"type": "address"
   442  			}
   443  		],
   444  		"payable": false,
   445  		"stateMutability": "nonpayable",
   446  		"type": "constructor"
   447  	}
   448  ]
   449  `
   450  )