github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/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/kisexp/xdchain/accounts/abi" 11 "github.com/kisexp/xdchain/common" 12 "github.com/kisexp/xdchain/common/hexutil" 13 "github.com/kisexp/xdchain/core" 14 "github.com/kisexp/xdchain/core/rawdb" 15 "github.com/kisexp/xdchain/core/state" 16 "github.com/kisexp/xdchain/core/types" 17 "github.com/kisexp/xdchain/core/vm" 18 "github.com/kisexp/xdchain/log" 19 "github.com/kisexp/xdchain/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 )