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 )