EIP-XXXX: AuthCreate

This commit is contained in:
yukino.xin 2024-04-23 01:59:37 +08:00
parent e6689fe090
commit 8c04f95f1e
12 changed files with 115 additions and 1 deletions

View file

@ -268,6 +268,8 @@ const (
GasChangeCallStorageColdAccess GasChangeReason = 13 GasChangeCallStorageColdAccess GasChangeReason = 13
// GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert. // GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert.
GasChangeCallFailedExecution GasChangeReason = 14 GasChangeCallFailedExecution GasChangeReason = 14
// GasChangeContractCreation is the amount of gas that will be burned for a AUTH_CREATE.
GasChangeCallAuthCreation GasChangeReason = 15
// GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as // GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as
// it will be "manually" tracked by a direct emit of the gas change event. // it will be "manually" tracked by a direct emit of the gas change event.

View file

@ -319,3 +319,14 @@ func enable6780(jt *JumpTable) {
maxStack: maxStack(1, 0), maxStack: maxStack(1, 0),
} }
} }
func enableXXXX(jt *JumpTable) {
jt[AUTH_CREATE] = &operation{
execute: opAuthCreate,
constantGas: params.AuthCreateGas,
dynamicGas: gasAuthCreate,
minStack: minStack(3, 1),
maxStack: maxStack(3, 1),
memorySize: memoryAuthCreate,
}
}

View file

@ -38,6 +38,7 @@ var (
ErrGasUintOverflow = errors.New("gas uint64 overflow") ErrGasUintOverflow = errors.New("gas uint64 overflow")
ErrInvalidCode = errors.New("invalid code: must not begin with 0xef") ErrInvalidCode = errors.New("invalid code: must not begin with 0xef")
ErrNonceUintOverflow = errors.New("nonce uint64 overflow") ErrNonceUintOverflow = errors.New("nonce uint64 overflow")
ErrAuthCreateSigType = errors.New("auth_create signature type not found ")
// errStopToken is an internal token indicating interpreter loop termination, // errStopToken is an internal token indicating interpreter loop termination,
// never returned to outside callers. // never returned to outside callers.

View file

@ -523,6 +523,36 @@ func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2) return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2)
} }
func (evm *EVM) AuthCreate(caller ContractRef, data []byte, gas uint64, endowment *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
if data[0] >= 4 {
return nil, common.Address{}, 0, ErrAuthCreateSigType
}
code := make([]byte, len(data)-65)
copy(code[:], data[65:])
codeAndHash := &codeAndHash{code: code}
sig := make([]byte, 65)
copy(sig, data)
msg := []byte{params.AuthCreateMagic}
msg = append(msg, common.LeftPadBytes(evm.chainConfig.ChainID.Bytes(), 32)...)
msg = append(msg, codeAndHash.Hash().Bytes()...)
msg = crypto.Keccak256(msg)
sig = append(sig[1:], sig[0])
pub, err := crypto.Ecrecover(msg, sig)
if err != nil {
return nil, common.Address{}, 0, err
}
var eoaAddr common.Address
copy(eoaAddr[:], crypto.Keccak256(pub[1:])[12:])
evm.StateDB.SetNonce(eoaAddr, 0)
return evm.create(caller, codeAndHash, gas, endowment, eoaAddr, AUTH_CREATE)
}
// ChainConfig returns the environment's chain configuration // ChainConfig returns the environment's chain configuration
func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }

View file

@ -484,3 +484,20 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
} }
return gas, nil return gas, nil
} }
func gasAuthCreate(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
gas, err := memoryGasCost(mem, memorySize)
if err != nil {
return 0, err
}
size, overflow := stack.Back(2).Uint64WithOverflow()
if overflow || size > params.MaxInitCodeSize {
return 0, ErrGasUintOverflow
}
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
moreGas := (params.InitCodeWordGas + params.Keccak256WordGas) * ((size + 31) / 32)
if gas, overflow = math.SafeAdd(gas, moreGas); overflow {
return 0, ErrGasUintOverflow
}
return gas, nil
}

View file

@ -652,6 +652,40 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
return nil, nil return nil, nil
} }
func opAuthCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
return nil, ErrWriteProtection
}
var (
endowment = scope.Stack.pop()
offset, size = scope.Stack.pop(), scope.Stack.pop()
data = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
gas = scope.Contract.Gas
)
// Apply EIP150
gas -= gas / 64
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallAuthCreation)
// reuse size int for stackvalue
stackvalue := size
res, addr, returnGas, suberr := interpreter.evm.AuthCreate(scope.Contract, data, gas, &endowment)
// 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.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
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 opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
stack := scope.Stack stack := scope.Stack
// Pop gas. The actual gas in interpreter.evm.callGasTemp. // Pop gas. The actual gas in interpreter.evm.callGasTemp.

View file

@ -99,6 +99,8 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
// If jump table was not initialised we set the default one. // If jump table was not initialised we set the default one.
var table *JumpTable var table *JumpTable
switch { switch {
case evm.chainRules.IsPrague:
table = &pragueInstructionSet
case evm.chainRules.IsCancun: case evm.chainRules.IsCancun:
table = &cancunInstructionSet table = &cancunInstructionSet
case evm.chainRules.IsShanghai: case evm.chainRules.IsShanghai:

View file

@ -57,6 +57,7 @@ var (
mergeInstructionSet = newMergeInstructionSet() mergeInstructionSet = newMergeInstructionSet()
shanghaiInstructionSet = newShanghaiInstructionSet() shanghaiInstructionSet = newShanghaiInstructionSet()
cancunInstructionSet = newCancunInstructionSet() cancunInstructionSet = newCancunInstructionSet()
pragueInstructionSet = newPraugeInstructionSet()
) )
// JumpTable contains the EVM opcodes supported at a given fork. // JumpTable contains the EVM opcodes supported at a given fork.
@ -80,6 +81,12 @@ func validate(jt JumpTable) JumpTable {
return jt return jt
} }
func newPraugeInstructionSet() JumpTable {
instructionSet := newCancunInstructionSet()
enableXXXX(&instructionSet) // EIP-XXXX AuthCreate
return validate(instructionSet)
}
func newCancunInstructionSet() JumpTable { func newCancunInstructionSet() JumpTable {
instructionSet := newShanghaiInstructionSet() instructionSet := newShanghaiInstructionSet()
enable4844(&instructionSet) // EIP-4844 (BLOBHASH opcode) enable4844(&instructionSet) // EIP-4844 (BLOBHASH opcode)

View file

@ -64,6 +64,10 @@ func memoryCreate2(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(1), stack.Back(2)) return calcMemSize64(stack.Back(1), stack.Back(2))
} }
func memoryAuthCreate(stack *Stack) (uint64, bool) {
return calcMemSize64(stack.Back(1), stack.Back(2))
}
func memoryCall(stack *Stack) (uint64, bool) { func memoryCall(stack *Stack) (uint64, bool) {
x, overflow := calcMemSize64(stack.Back(5), stack.Back(6)) x, overflow := calcMemSize64(stack.Back(5), stack.Back(6))
if overflow { if overflow {

View file

@ -217,6 +217,7 @@ const (
RETURN OpCode = 0xf3 RETURN OpCode = 0xf3
DELEGATECALL OpCode = 0xf4 DELEGATECALL OpCode = 0xf4
CREATE2 OpCode = 0xf5 CREATE2 OpCode = 0xf5
AUTH_CREATE OpCode = 0xf6
STATICCALL OpCode = 0xfa STATICCALL OpCode = 0xfa
REVERT OpCode = 0xfd REVERT OpCode = 0xfd
@ -391,6 +392,7 @@ var opCodeToString = [256]string{
CALLCODE: "CALLCODE", CALLCODE: "CALLCODE",
DELEGATECALL: "DELEGATECALL", DELEGATECALL: "DELEGATECALL",
CREATE2: "CREATE2", CREATE2: "CREATE2",
AUTH_CREATE: "AUTH_CREATE",
STATICCALL: "STATICCALL", STATICCALL: "STATICCALL",
REVERT: "REVERT", REVERT: "REVERT",
INVALID: "INVALID", INVALID: "INVALID",
@ -548,6 +550,7 @@ var stringToOp = map[string]OpCode{
"LOG4": LOG4, "LOG4": LOG4,
"CREATE": CREATE, "CREATE": CREATE,
"CREATE2": CREATE2, "CREATE2": CREATE2,
"AUTH_CREATE": AUTH_CREATE,
"CALL": CALL, "CALL": CALL,
"RETURN": RETURN, "RETURN": RETURN,
"CALLCODE": CALLCODE, "CALLCODE": CALLCODE,

View file

@ -184,6 +184,7 @@ var (
GrayGlacierBlock: big.NewInt(0), GrayGlacierBlock: big.NewInt(0),
ShanghaiTime: newUint64(0), ShanghaiTime: newUint64(0),
CancunTime: newUint64(0), CancunTime: newUint64(0),
PragueTime: newUint64(0),
TerminalTotalDifficulty: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0),
TerminalTotalDifficultyPassed: true, TerminalTotalDifficultyPassed: true,
} }

View file

@ -86,6 +86,7 @@ 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. 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. CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
Create2Gas uint64 = 32000 // Once per CREATE2 operation Create2Gas uint64 = 32000 // Once per CREATE2 operation
AuthCreateGas uint64 = 32000 // Once per CREATE2 operation
SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct 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. 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.
@ -187,5 +188,6 @@ var (
// BeaconRootsAddress is the address where historical beacon roots are stored as per EIP-4788 // BeaconRootsAddress is the address where historical beacon roots are stored as per EIP-4788
BeaconRootsAddress = common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02") BeaconRootsAddress = common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02")
// SystemAddress is where the system-transaction is sent from as per EIP-4788 // SystemAddress is where the system-transaction is sent from as per EIP-4788
SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe") SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")
AuthCreateMagic = byte(0x04)
) )