mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-30 08:33:45 +00:00
134 lines
4 KiB
Go
134 lines
4 KiB
Go
package vm
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/holiman/uint256"
|
|
"math/big"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
)
|
|
|
|
// Wrapper type which allows PrecompiledContract to be used as PrecompiledContractWithCtx
|
|
type precompileWrapper struct {
|
|
PrecompiledContract
|
|
}
|
|
|
|
func (pw precompileWrapper) Run(input []byte, ctx *precompileContext) ([]byte, error) {
|
|
return pw.PrecompiledContract.Run(input)
|
|
}
|
|
|
|
// Interface for precompiled contract with ctx object allowing for writes to state.
|
|
type PrecompiledContractWithCtx interface {
|
|
RequiredGas(input []byte) uint64
|
|
Run(input []byte, ctx *precompileContext) ([]byte, error)
|
|
}
|
|
|
|
type precompileContext struct {
|
|
*BlockContext
|
|
*params.Rules
|
|
|
|
caller common.Address
|
|
evm *EVM
|
|
}
|
|
|
|
func NewContext(caller common.Address, evm *EVM) *precompileContext {
|
|
return &precompileContext{
|
|
BlockContext: &evm.Context,
|
|
Rules: &evm.chainRules,
|
|
caller: caller,
|
|
evm: evm,
|
|
}
|
|
}
|
|
|
|
var vmBlockCtx = BlockContext{
|
|
CanTransfer: func(db StateDB, addr common.Address, amount *uint256.Int) bool {
|
|
return db.GetBalance(addr).Cmp(amount) >= 0
|
|
},
|
|
Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {
|
|
panic("transfer: not implemented")
|
|
},
|
|
GetHash: func(u uint64) common.Hash {
|
|
panic("getHash: not implemented")
|
|
},
|
|
Coinbase: common.Address{},
|
|
BlockNumber: new(big.Int).SetUint64(10),
|
|
Time: uint64(time.Now().Unix()),
|
|
}
|
|
|
|
var vmTxCtx = TxContext{
|
|
GasPrice: common.Big1,
|
|
Origin: common.HexToAddress("a11ce"),
|
|
}
|
|
|
|
// Create a global mock EVM for use in the following tests.
|
|
var mockEVM = &EVM{
|
|
Context: vmBlockCtx,
|
|
TxContext: vmTxCtx,
|
|
}
|
|
|
|
// Native token mint precompile to make bridging to native token possible.
|
|
type mint struct{}
|
|
|
|
func (c *mint) RequiredGas(input []byte) uint64 {
|
|
// TODO: determine appropriate gas cost
|
|
return 100
|
|
}
|
|
|
|
// Predetermined create2 address of whitelist contract with exclusive mint/burn privileges.
|
|
// This address assumes deployer is 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266.
|
|
const whitelistCreate2Addr = "0x5D1415C0973034d162F5FEcF19B50dA057057e29"
|
|
|
|
func (c *mint) Run(input []byte, ctx *precompileContext) ([]byte, error) {
|
|
|
|
if ctx.caller != common.HexToAddress(whitelistCreate2Addr) {
|
|
log.Error("Error parsing transfer: caller not whitelisted")
|
|
return nil, fmt.Errorf("Error parsing transfer: caller not whitelisted")
|
|
}
|
|
|
|
mintTo := common.BytesToAddress(input[0:32])
|
|
value, err := uint256.FromHex(hexutil.Encode(input[32:64]))
|
|
if err != nil {
|
|
log.Error("Error parsing transfer: unable to parse value from " + hexutil.Encode(input[32:64]))
|
|
return nil, fmt.Errorf("Error parsing transfer: unable to parse value from " + hexutil.Encode(input[32:64]))
|
|
}
|
|
|
|
// Create native token out of thin air
|
|
ctx.evm.StateDB.AddBalance(mintTo, value)
|
|
|
|
return input, nil
|
|
}
|
|
|
|
// Native token burn precompile to make bridging back to L1 possible.
|
|
type burn struct{}
|
|
|
|
func (c *burn) RequiredGas(input []byte) uint64 {
|
|
// TODO: determine appropriate gas cost
|
|
return 100
|
|
}
|
|
|
|
// Note ctx.CanTransfer method obtains an incorrect balance w.r.t "burnFrom" address,
|
|
// specifically during estimateGas. The CanTransfer check was therefore removed,
|
|
// and the calling contract is responsible for checking balance.
|
|
func (c *burn) Run(input []byte, ctx *precompileContext) ([]byte, error) {
|
|
|
|
if ctx.caller != common.HexToAddress(whitelistCreate2Addr) {
|
|
log.Error("Error parsing transfer: caller not whitelisted")
|
|
return nil, fmt.Errorf("Error parsing transfer: caller not whitelisted")
|
|
}
|
|
|
|
burnFrom := common.BytesToAddress(input[0:32])
|
|
|
|
value, err := uint256.FromHex(hexutil.Encode(input[32:64]))
|
|
if err != nil {
|
|
log.Error("Error parsing transfer: unable to parse value from " + hexutil.Encode(input[32:64]))
|
|
return nil, fmt.Errorf("Error parsing transfer: unable to parse value from " + hexutil.Encode(input[32:64]))
|
|
}
|
|
|
|
ctx.evm.StateDB.SubBalance(burnFrom, value)
|
|
|
|
return input, nil
|
|
}
|