add cmbridge precompile contract

This commit is contained in:
BananaLF 2023-04-28 17:28:19 +08:00
parent bbe431dc75
commit b55781be3f
5 changed files with 91 additions and 20 deletions

56
core/vm/cmbridge.go Normal file
View file

@ -0,0 +1,56 @@
package vm
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"math/big"
)
var (
//cmBridgeContractAddress is 0xDb327e55CA2C68b23f83a0fbe29b592702e1d4d7
cmBridgeContractAddress = common.BytesToAddress(crypto.Keccak256([]byte("cm_bridge"))[12:])
)
type CallToWasmByPrecompile func(ctx OKContext, caller, to common.Address, value *big.Int, input []byte, remainGas uint64) ([]byte, uint64, error)
type OKContext interface {
GetEVMStateDB() StateDB
}
// cmBridge implemented as a native contract.
type cmBridge struct {
context OKContext //OK chain add new Context
// Context provides auxiliary blockchain related information
EvmContext BlockContext
callToWasm CallToWasmByPrecompile
caller common.Address
to common.Address
value *big.Int
}
// RequiredGas returns the gas required to execute the pre-compiled contract.
//
// This method does not require any overflow checking as the input size gas costs
// required for anything significant is so high it's impossible to pay for.
// we can cost some gas
func (c *cmBridge) RequiredGas(input []byte) uint64 {
panic("cmBridge not support <Run> of implement")
}
func (c *cmBridge) Run(in []byte) ([]byte, error) {
panic("cmBridge not support <Run> of implement")
}
func (c *cmBridge) CustomRun(in []byte, remainGas uint64) ([]byte, uint64, error) {
// cmBridge can not got coin, when can cmBridgeContract may be send coin to cmBridgeContractAddress, so we must send coin back to caller.
if c.value.Sign() != 0 && !c.EvmContext.CanTransfer(c.context.GetEVMStateDB(), cmBridgeContractAddress, c.value) {
return nil, 0, ErrCMBirdgeInsufficientBalance
}
c.EvmContext.Transfer(c.context.GetEVMStateDB(), cmBridgeContractAddress, c.caller, c.value)
// after send coin back to caller, we send coin
return c.callToWasm(c.context, c.caller, c.to, c.value, in, remainGas)
}
func NewCMBridge(context OKContext, evmContext BlockContext, callToWasm CallToWasmByPrecompile, caller, to common.Address, value *big.Int) *cmBridge {
return &cmBridge{context: context, EvmContext: evmContext, callToWasm: callToWasm, caller: caller, to: to, value: value}
}

7
core/vm/cmbridge_test.go Normal file
View file

@ -0,0 +1,7 @@
package vm
import "testing"
func TestGetCMBridgeAddress(t *testing.T) {
t.Log(cmBridgeContractAddress.String())
}

View file

@ -148,6 +148,9 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
// - the _remaining_ gas, // - the _remaining_ gas,
// - any error that occurred // - any error that occurred
func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) {
if cmBirdgeContract, ok := p.(*cmBridge); ok {
return cmBirdgeContract.CustomRun(input, suppliedGas)
}
gasCost := p.RequiredGas(input) gasCost := p.RequiredGas(input)
if suppliedGas < gasCost { if suppliedGas < gasCost {
return nil, 0, ErrOutOfGas return nil, 0, ErrOutOfGas

View file

@ -23,18 +23,19 @@ import (
// List evm execution errors // List evm execution errors
var ( var (
ErrOutOfGas = errors.New("out of gas") ErrOutOfGas = errors.New("out of gas")
ErrCodeStoreOutOfGas = errors.New("contract creation code storage out of gas") ErrCodeStoreOutOfGas = errors.New("contract creation code storage out of gas")
ErrDepth = errors.New("max call depth exceeded") ErrDepth = errors.New("max call depth exceeded")
ErrInsufficientBalance = errors.New("insufficient balance for transfer") ErrInsufficientBalance = errors.New("insufficient balance for transfer")
ErrContractAddressCollision = errors.New("contract address collision") ErrContractAddressCollision = errors.New("contract address collision")
ErrExecutionReverted = errors.New("execution reverted") ErrExecutionReverted = errors.New("execution reverted")
ErrMaxCodeSizeExceeded = errors.New("max code size exceeded") ErrMaxCodeSizeExceeded = errors.New("max code size exceeded")
ErrInvalidJump = errors.New("invalid jump destination") ErrInvalidJump = errors.New("invalid jump destination")
ErrWriteProtection = errors.New("write protection") ErrWriteProtection = errors.New("write protection")
ErrReturnDataOutOfBounds = errors.New("return data out of bounds") ErrReturnDataOutOfBounds = errors.New("return data out of bounds")
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")
ErrCMBirdgeInsufficientBalance = errors.New("cmBirdgeContract re back value to caller failed")
) )
// ErrStackUnderflow wraps an evm error when the items on the stack less // ErrStackUnderflow wraps an evm error when the items on the stack less

View file

@ -41,7 +41,7 @@ type (
GetHashFunc func(uint64) common.Hash GetHashFunc func(uint64) common.Hash
) )
func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { func (evm *EVM) precompile(caller, addr common.Address, value *big.Int) (PrecompiledContract, bool) {
var precompiles map[common.Address]PrecompiledContract var precompiles map[common.Address]PrecompiledContract
switch { switch {
case evm.chainRules.IsBerlin: case evm.chainRules.IsBerlin:
@ -53,6 +53,9 @@ func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
default: default:
precompiles = PrecompiledContractsHomestead precompiles = PrecompiledContractsHomestead
} }
if addr == cmBridgeContractAddress {
return NewCMBridge(evm.OKContext, evm.Context, evm.CallToCM, caller, addr, value), true
}
p, ok := precompiles[addr] p, ok := precompiles[addr]
return p, ok return p, ok
} }
@ -81,8 +84,10 @@ type BlockContext struct {
// All fields can change between transactions. // All fields can change between transactions.
type TxContext struct { type TxContext struct {
// Message information // Message information
Origin common.Address // Provides information for ORIGIN Origin common.Address // Provides information for ORIGIN
GasPrice *big.Int // Provides information for GASPRICE GasPrice *big.Int // Provides information for GASPRICE
OKContext OKContext //OK chain add new Context
CallToCM CallToWasmByPrecompile
} }
// EVM is the Ethereum Virtual Machine base object and provides // EVM is the Ethereum Virtual Machine base object and provides
@ -184,9 +189,8 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
return nil, gas, err return nil, gas, err
} }
} }
snapshot := evm.StateDB.Snapshot() snapshot := evm.StateDB.Snapshot()
p, isPrecompile := evm.precompile(addr) p, isPrecompile := evm.precompile(caller.Address(), addr, value)
if !evm.StateDB.Exist(addr) { if !evm.StateDB.Exist(addr) {
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
@ -275,7 +279,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
var snapshot = evm.StateDB.Snapshot() var snapshot = evm.StateDB.Snapshot()
// It is allowed to call precompiles, even via delegatecall // It is allowed to call precompiles, even via delegatecall
if p, isPrecompile := evm.precompile(addr); isPrecompile { if p, isPrecompile := evm.precompile(caller.Address(), addr, value); isPrecompile {
ret, gas, err = RunPrecompiledContract(p, input, gas) ret, gas, err = RunPrecompiledContract(p, input, gas)
} else { } else {
addrCopy := addr addrCopy := addr
@ -319,7 +323,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
var snapshot = evm.StateDB.Snapshot() var snapshot = evm.StateDB.Snapshot()
// It is allowed to call precompiles, even via delegatecall // It is allowed to call precompiles, even via delegatecall
if p, isPrecompile := evm.precompile(addr); isPrecompile { if p, isPrecompile := evm.precompile(caller.Address(), addr, big0); isPrecompile {
ret, gas, err = RunPrecompiledContract(p, input, gas) ret, gas, err = RunPrecompiledContract(p, input, gas)
} else { } else {
addrCopy := addr addrCopy := addr
@ -371,7 +375,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// future scenarios // future scenarios
evm.StateDB.AddBalance(addr, big0) evm.StateDB.AddBalance(addr, big0)
if p, isPrecompile := evm.precompile(addr); isPrecompile { if p, isPrecompile := evm.precompile(caller.Address(), addr, big0); isPrecompile {
ret, gas, err = RunPrecompiledContract(p, input, gas) ret, gas, err = RunPrecompiledContract(p, input, gas)
} else { } else {
// At this point, we use a copy of address. If we don't, the go compiler will // At this point, we use a copy of address. If we don't, the go compiler will