From a48e4fef54da5868fc39ea0d593c2267d376a13a Mon Sep 17 00:00:00 2001 From: racytech Date: Tue, 21 Nov 2023 21:28:38 +0600 Subject: [PATCH] CREATE3 impl --- core/vm/eips.go | 71 +++++++++++++++++++++++++++++++++ core/vm/eof.go | 7 ++-- core/vm/evm.go | 10 +++++ core/vm/opcodes.go | 82 +++++++++++++++++++-------------------- params/protocol_params.go | 2 + 5 files changed, 128 insertions(+), 44 deletions(-) diff --git a/core/vm/eips.go b/core/vm/eips.go index d59749b8842..1f29782431a 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -423,6 +423,23 @@ func enableEOF(jt *JumpTable) { numPush: 0, memorySize: memoryDataCopy, } + jt[CREATE3] = &operation{ + execute: opCreate3, + constantGas: params.Create3Gas, + // dynamicGas: gasCreate2, + numPop: 4, + numPush: 1, + memorySize: memoryCreate2, + } + jt[CREATE4] = &operation{ + execute: opCreate4, + constantGas: params.Create4Gas, + // dynamicGas: gasCreate2, + numPop: 4, + numPush: 1, + memorySize: memoryCreate2, + } + jt[RETURNCONTRACT] = &operation{} } // opRjump implements the rjump opcode. @@ -587,3 +604,57 @@ func opDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ return nil, nil } + +func opCreate3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + if interpreter.readOnly { + return nil, ErrWriteProtection + } + var ( + code = scope.Contract.CodeAt(scope.CodeSection) + initContainerIdx = int(code[*pc+1]) + endowment = scope.Stack.Pop() + salt = scope.Stack.Pop() + offset, size = scope.Stack.Pop(), scope.Stack.Pop() + inputOffset = offset.Uint64() + inputSize = size.Uint64() + gas = scope.Contract.Gas + input = []byte{} + initContainer = scope.Contract.Container.SubContainer[initContainerIdx] + ) + + if inputSize > 0 { + input = scope.Memory.GetCopy(int64(inputOffset), int64(inputSize)) + } + // Apply EIP150 + gas -= gas / 64 + scope.Contract.UseGas(gas) + + stackValue := size + + res, addr, returnGas, suberr := interpreter.evm.Create3(scope.Contract, input, initContainer, gas, &endowment, &salt) + + // Push item on the stack based on the returned error. + if suberr != nil { + stackValue.Clear() + } else { + stackValue.SetBytes(addr.Bytes()) + } + + scope.Stack.Push(&stackValue) + scope.Contract.Gas += returnGas + + if suberr == ErrExecutionReverted { + interpreter.returnData = res // set REVERT data to return data buffer + return res, nil + } + interpreter.returnData = nil // clear dirty return data buffer + return nil, nil +} + +func opCreate4(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return nil, nil +} + +func opReturnContract(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + return nil, nil +} diff --git a/core/vm/eof.go b/core/vm/eof.go index 8a299e9edbb..5ed16400ab2 100644 --- a/core/vm/eof.go +++ b/core/vm/eof.go @@ -79,9 +79,10 @@ func isEOFVersion1(code []byte) bool { // Container is an EOF container object. type Container struct { - Types []*FunctionMetadata - Code [][]byte - Data []byte + Types []*FunctionMetadata + Code [][]byte + SubContainer [][]byte + Data []byte } // FunctionMetadata is an EOF function signature. diff --git a/core/vm/evm.go b/core/vm/evm.go index b5dce6e73ac..93717bcc368 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -500,6 +500,16 @@ func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment * return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2, true /* incrementNonce */, isCallerEOF) } +func (evm *EVM) Create3(caller ContractRef, code, initContainer []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr libcommon.Address, leftOverGas uint64, err error) { + // TODO + return nil, libcommon.Address{}, 0, nil +} + +func (evm *EVM) Create4(caller ContractRef, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr libcommon.Address, leftOverGas uint64, err error) { + // TODO + return nil, libcommon.Address{}, 0, nil +} + // SysCreate is a special (system) contract creation methods for genesis constructors. // Unlike the normal Create & Create2, it doesn't increment caller's nonce. func (evm *EVM) SysCreate(caller ContractRef, code []byte, gas uint64, endowment *uint256.Int, contractAddr libcommon.Address) (ret []byte, leftOverGas uint64, err error) { diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 8910421a23e..641d630dcd7 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -207,21 +207,21 @@ const ( // 0xe0 range - eof ops. const ( - RJUMP OpCode = 0xe0 - RJUMPI OpCode = 0xe1 - RJUMPV OpCode = 0xe2 - CALLF OpCode = 0xe3 - RETF OpCode = 0xe4 - JUMPF OpCode = 0xe5 - DUPN OpCode = 0xe6 - SWAPN OpCode = 0xe7 - DATALOAD OpCode = 0xe8 - DATALOADN OpCode = 0xe9 - DATASIZE OpCode = 0xea - DATACOPY OpCode = 0xeb - // CREATE3 OpCode = 0xec - // CREATE4 OpCode = 0xed - // RETURNCONTRACT OpCode = 0xee + RJUMP OpCode = 0xe0 + RJUMPI OpCode = 0xe1 + RJUMPV OpCode = 0xe2 + CALLF OpCode = 0xe3 + RETF OpCode = 0xe4 + JUMPF OpCode = 0xe5 + DUPN OpCode = 0xe6 + SWAPN OpCode = 0xe7 + DATALOAD OpCode = 0xe8 + DATALOADN OpCode = 0xe9 + DATASIZE OpCode = 0xea + DATACOPY OpCode = 0xeb + CREATE3 OpCode = 0xec + CREATE4 OpCode = 0xed + RETURNCONTRACT OpCode = 0xee ) // 0xf0 range - closures. @@ -398,21 +398,21 @@ var opCodeToString = map[OpCode]string{ LOG4: "LOG4", // 0xe0 range. - RJUMP: "RJUMP", - RJUMPI: "RJUMPI", - RJUMPV: "RJUMPV", - CALLF: "CALLF", - RETF: "RETF", - JUMPF: "JUMPF", - DUPN: "DUPN", - SWAPN: "SWAPN", - DATALOAD: "DATALOAD", - DATALOADN: "DATALOADN", - DATASIZE: "DATASIZE", - DATACOPY: "DATACOPY", - // CREATE3: "CREATE3", - // CREATE4: "CREATE4", - // RETURNCONTRACT: "RETURNCONTRACT", + RJUMP: "RJUMP", + RJUMPI: "RJUMPI", + RJUMPV: "RJUMPV", + CALLF: "CALLF", + RETF: "RETF", + JUMPF: "JUMPF", + DUPN: "DUPN", + SWAPN: "SWAPN", + DATALOAD: "DATALOAD", + DATALOADN: "DATALOADN", + DATASIZE: "DATASIZE", + DATACOPY: "DATACOPY", + CREATE3: "CREATE3", + CREATE4: "CREATE4", + RETURNCONTRACT: "RETURNCONTRACT", // 0xf0 range. CREATE: "CREATE", @@ -590,17 +590,17 @@ var stringToOp = map[string]OpCode{ "DATALOADN": DATALOADN, "DATASIZE": DATASIZE, "DATACOPY": DATACOPY, - // "CREATE3": CREATE3, - // "CREATE4": CREATE4, - // "RETURNCONTRACT": RETURNCONTRACT, - "CREATE": CREATE, - "CREATE2": CREATE2, - "CALL": CALL, - "RETURN": RETURN, - "CALLCODE": CALLCODE, - "REVERT": REVERT, - "INVALID": INVALID, - "SELFDESTRUCT": SELFDESTRUCT, + "CREATE3": CREATE3, + "CREATE4": CREATE4, + "RETURNCONTRACT": RETURNCONTRACT, + "CREATE": CREATE, + "CREATE2": CREATE2, + "CALL": CALL, + "RETURN": RETURN, + "CALLCODE": CALLCODE, + "REVERT": REVERT, + "INVALID": INVALID, + "SELFDESTRUCT": SELFDESTRUCT, } // StringToOp finds the opcode whose name is stored in `str`. diff --git a/params/protocol_params.go b/params/protocol_params.go index 33ffda9a94c..b388514cdf5 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -84,6 +84,8 @@ const ( LogTopicGas uint64 = 375 // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas. CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction. Create2Gas uint64 = 32000 // Once per CREATE2 operation + Create3Gas uint64 = 32000 // Once per CREATE3 operation + Create4Gas uint64 = 32000 // Once per CREATE4 operation SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation. MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.