mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
moveTo only for precompiles
This commit is contained in:
parent
8e026758fe
commit
a0d2706907
3 changed files with 28 additions and 88 deletions
|
|
@ -902,10 +902,12 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
|||
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||
// Apply the customization rules if required.
|
||||
if config != nil {
|
||||
if err := config.StateOverrides.Apply(statedb); err != nil {
|
||||
config.BlockOverrides.Apply(&vmctx)
|
||||
rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber, vmctx.Random != nil, vmctx.Time)
|
||||
precompiles := vm.ActivePrecompiledContracts(rules)
|
||||
if err := config.StateOverrides.Apply(statedb, precompiles); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.BlockOverrides.Apply(&vmctx)
|
||||
}
|
||||
// Execute the trace
|
||||
msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee(), true)
|
||||
|
|
|
|||
|
|
@ -873,95 +873,30 @@ type OverrideAccount struct {
|
|||
Balance **hexutil.Big `json:"balance"`
|
||||
State *map[common.Hash]common.Hash `json:"state"`
|
||||
StateDiff *map[common.Hash]common.Hash `json:"stateDiff"`
|
||||
MoveTo *common.Address `json:"moveToAddress"`
|
||||
MovePrecompileTo *common.Address `json:"movePrecompileToAddress"`
|
||||
}
|
||||
|
||||
// StateOverride is the collection of overridden accounts.
|
||||
type StateOverride map[common.Address]OverrideAccount
|
||||
|
||||
// Apply overrides the fields of specified accounts into the given state.
|
||||
func (diff *StateOverride) Apply(state *state.StateDB) error {
|
||||
if diff == nil {
|
||||
return nil
|
||||
}
|
||||
for addr, account := range *diff {
|
||||
// Override account nonce.
|
||||
if account.Nonce != nil {
|
||||
state.SetNonce(addr, uint64(*account.Nonce))
|
||||
}
|
||||
// Override account(contract) code.
|
||||
if account.Code != nil {
|
||||
state.SetCode(addr, *account.Code)
|
||||
}
|
||||
// Override account balance.
|
||||
if account.Balance != nil {
|
||||
state.SetBalance(addr, (*big.Int)(*account.Balance))
|
||||
}
|
||||
if account.State != nil && account.StateDiff != nil {
|
||||
return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
|
||||
}
|
||||
// Replace entire state if caller requires.
|
||||
if account.State != nil {
|
||||
state.SetStorage(addr, *account.State)
|
||||
}
|
||||
// Apply state diff into specified accounts.
|
||||
if account.StateDiff != nil {
|
||||
for key, value := range *account.StateDiff {
|
||||
state.SetState(addr, key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now finalize the changes. Finalize is normally performed between transactions.
|
||||
// By using finalize, the overrides are semantically behaving as
|
||||
// if they were created in a transaction just before the tracing occur.
|
||||
state.Finalise(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyMulticall overrides the fields of specified accounts into the given state.
|
||||
// TODO: consider MoveTo by address mapping
|
||||
func (diff *StateOverride) ApplyMulticall(state *state.StateDB, precompiles vm.PrecompiledContracts) error {
|
||||
func (diff *StateOverride) Apply(state *state.StateDB, precompiles vm.PrecompiledContracts) error {
|
||||
if diff == nil {
|
||||
return nil
|
||||
}
|
||||
for addr, account := range *diff {
|
||||
p, isPrecompile := precompiles[addr]
|
||||
// The MoveTo feature makes it possible to replace precompiles and EVM
|
||||
// contracts in all the following configurations:
|
||||
// 1. Precompile -> Precompile
|
||||
// 2. Precompile -> EVM contract
|
||||
// 3. EVM contract -> Precompile
|
||||
// 4. EVM contract -> EVM contract
|
||||
if account.MoveTo != nil {
|
||||
if isPrecompile {
|
||||
// Clear destination account which may be an EVM contract.
|
||||
if !state.Empty(*account.MoveTo) {
|
||||
state.SetCode(*account.MoveTo, nil)
|
||||
state.SetNonce(*account.MoveTo, 0)
|
||||
state.SetBalance(*account.MoveTo, big.NewInt(0))
|
||||
state.SetStorage(*account.MoveTo, map[common.Hash]common.Hash{})
|
||||
}
|
||||
// If destination is a precompile, it will be simply replaced.
|
||||
precompiles[*account.MoveTo] = p
|
||||
} else {
|
||||
state.SetBalance(*account.MoveTo, state.GetBalance(addr))
|
||||
state.SetNonce(*account.MoveTo, state.GetNonce(addr))
|
||||
state.SetCode(*account.MoveTo, state.GetCode(addr))
|
||||
// Copy storage over
|
||||
// TODO: Use snaps
|
||||
state.ForEachStorage(addr, func(key, value common.Hash) bool {
|
||||
state.SetState(*account.MoveTo, key, value)
|
||||
return true
|
||||
})
|
||||
// Clear source storage
|
||||
state.SetStorage(addr, map[common.Hash]common.Hash{})
|
||||
if precompiles[*account.MoveTo] != nil {
|
||||
delete(precompiles, *account.MoveTo)
|
||||
}
|
||||
// The MoveTo feature makes it possible to move a precompile
|
||||
// code to another address. If the target address is another precompile
|
||||
// the code for the latter is lost for this session.
|
||||
// Note the destination account is not cleared upon move.
|
||||
if account.MovePrecompileTo != nil {
|
||||
if !isPrecompile {
|
||||
return fmt.Errorf("account %s is not a precompile", addr.Hex())
|
||||
}
|
||||
precompiles[*account.MovePrecompileTo] = p
|
||||
}
|
||||
if isPrecompile {
|
||||
// Now that the contract is moved it can be deleted.
|
||||
delete(precompiles, addr)
|
||||
}
|
||||
// Override account nonce.
|
||||
|
|
@ -1075,13 +1010,16 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
|
|||
if state == nil || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := overrides.Apply(state); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
|
||||
if blockOverrides != nil {
|
||||
blockOverrides.Apply(&blockCtx)
|
||||
}
|
||||
rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time)
|
||||
precompiles := vm.ActivePrecompiledContracts(rules).Copy()
|
||||
if err := overrides.Apply(state, precompiles); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Setup context so it may be cancelled the call has completed
|
||||
// or, in case of unmetered gas, setup a context with a timeout.
|
||||
var cancel context.CancelFunc
|
||||
|
|
@ -1264,7 +1202,7 @@ func (s *BlockChainAPI) MulticallV1(ctx context.Context, opts multicallOpts, blo
|
|||
blockContext = blockContexts[bi]
|
||||
hash := crypto.Keccak256Hash(blockContext.BlockNumber.Bytes())
|
||||
// State overrides are applied prior to execution of a block
|
||||
if err := block.StateOverrides.ApplyMulticall(state, precompiles); err != nil {
|
||||
if err := block.StateOverrides.Apply(state, precompiles); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results[bi] = blockResult{
|
||||
|
|
|
|||
|
|
@ -1115,7 +1115,7 @@ func TestMulticallV1(t *testing.T) {
|
|||
// }
|
||||
// }
|
||||
Code: hex2Bytes("365981600082378181f3"),
|
||||
MoveTo: &randomAccounts[2].addr,
|
||||
MovePrecompileTo: &randomAccounts[2].addr,
|
||||
},
|
||||
},
|
||||
Calls: []TransactionArgs{{
|
||||
|
|
|
|||
Loading…
Reference in a new issue