Skip to content

Commit

Permalink
core/vm: less allocations for various call variants (ethereum#21222)
Browse files Browse the repository at this point in the history
  • Loading branch information
gzliudan committed Sep 5, 2024
1 parent 3e4932e commit a92e0be
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 125 deletions.
28 changes: 23 additions & 5 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,29 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
}

// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
gas := p.RequiredGas(input)
if contract.UseGas(gas) {
return p.Run(input)
// It returns
// - the returned bytes,
// - the _remaining_ gas,
// - any error that occurred
func RunPrecompiledContract(evm *EVM, p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) {
if evm != nil {
if evm.chainConfig.IsTIPXDCXReceiver(evm.BlockNumber) {
switch p := p.(type) {
case *XDCxEpochPrice:
p.SetTradingState(evm.tradingStateDB)
case *XDCxLastPrice:
p.SetTradingState(evm.tradingStateDB)
}
}
}

gasCost := p.RequiredGas(input)
if suppliedGas < gasCost {
return nil, 0, ErrOutOfGas
}
return nil, ErrOutOfGas
suppliedGas -= gasCost
output, err := p.Run(input)
return output, suppliedGas, err
}

// ECRECOVER implemented as a native contract.
Expand Down Expand Up @@ -230,6 +247,7 @@ func (c *dataCopy) Run(in []byte) ([]byte, error) {
type bigModExp struct{}

var (
big0 = big.NewInt(0)
big1 = big.NewInt(1)
big4 = big.NewInt(4)
big8 = big.NewInt(8)
Expand Down
57 changes: 17 additions & 40 deletions core/vm/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ import (
"reflect"
"testing"

"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/params"

"github.com/XinFinOrg/XDPoSChain/common"
)

Expand Down Expand Up @@ -496,10 +492,9 @@ var blake2FTests = []precompiledTest{
func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
in := common.Hex2Bytes(test.input)
contract := NewContract(AccountRef(common.HexToAddress("1337")),
nil, new(big.Int), p.RequiredGas(in))
t.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(t *testing.T) {
if res, err := RunPrecompiledContract(p, in, contract); err != nil {
gas := p.RequiredGas(in)
t.Run(fmt.Sprintf("%s-Gas=%d", test.name, gas), func(t *testing.T) {
if res, _, err := RunPrecompiledContract(nil, p, in, gas); err != nil {
t.Error(err)
} else if common.Bytes2Hex(res) != test.expected {
t.Errorf("Expected %v, got %v", test.expected, common.Bytes2Hex(res))
Expand All @@ -513,21 +508,12 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
}

func testXDCxPrecompiled(addr string, test precompiledTest, t *testing.T) {
db := rawdb.NewMemoryDatabase()
stateCache := tradingstate.NewDatabase(db)
tradingStateDB, _ := tradingstate.New(common.Hash{}, stateCache)
tradingStateDB.SetLastPrice(tradingstate.GetTradingOrderBookHash(common.HexToAddress(BTCAddress), common.HexToAddress(USDTAddress)), BTCUSDTLastPrice)
tradingStateDB.SetMediumPriceBeforeEpoch(tradingstate.GetTradingOrderBookHash(common.HexToAddress(BTCAddress), common.HexToAddress(USDTAddress)), BTCUSDTEpochPrice)

evm := NewEVM(Context{BlockNumber: common.Big1}, nil, tradingStateDB, &params.ChainConfig{ByzantiumBlock: common.Big0}, Config{})
contractAddr := common.HexToAddress(addr)
p := PrecompiledContractsByzantium[contractAddr]
in := common.Hex2Bytes(test.input)
contract := NewContract(AccountRef(common.HexToAddress("1337")),
nil, new(big.Int), p.RequiredGas(in))
contract.SetCallCode(&contractAddr, common.Hash{}, []byte{})
t.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(t *testing.T) {
if res, err := run(evm, contract, in, false); err != nil {
gas := p.RequiredGas(in)
t.Run(fmt.Sprintf("%s-Gas=%d", test.name, gas), func(t *testing.T) {
if res, _, err := RunPrecompiledContract(nil, p, in, gas); err != nil {
t.Error(err)
} else if common.Bytes2Hex(res) != test.expected {
t.Errorf("Expected %v, got %v", test.expected, common.Bytes2Hex(res))
Expand All @@ -536,16 +522,12 @@ func testXDCxPrecompiled(addr string, test precompiledTest, t *testing.T) {
}

func testPrecompiledWithEmptyTradingState(addr string, test precompiledTest, t *testing.T) {
evm := NewEVM(Context{BlockNumber: common.Big1}, nil, nil, &params.ChainConfig{ByzantiumBlock: common.Big0}, Config{})

contractAddr := common.HexToAddress(addr)
p := PrecompiledContractsByzantium[contractAddr]
in := common.Hex2Bytes(test.input)
contract := NewContract(AccountRef(common.HexToAddress("1337")),
nil, new(big.Int), p.RequiredGas(in))
contract.SetCallCode(&contractAddr, common.Hash{}, []byte{})
t.Run(fmt.Sprintf("testPrecompiledWithEmptyTradingState-%s-Gas=%d", test.name, contract.Gas), func(t *testing.T) {
if res, err := run(evm, contract, in, false); err != nil {
gas := p.RequiredGas(in)
t.Run(fmt.Sprintf("testPrecompiledWithEmptyTradingState-%s-Gas=%d", test.name, gas), func(t *testing.T) {
if res, _, err := RunPrecompiledContract(nil, p, in, gas); err != nil {
t.Error(err)
} else if common.Bytes2Hex(res) != test.expected {
t.Errorf("Expected %v, got %v", test.expected, common.Bytes2Hex(res))
Expand All @@ -556,10 +538,10 @@ func testPrecompiledWithEmptyTradingState(addr string, test precompiledTest, t *
func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
in := common.Hex2Bytes(test.input)
contract := NewContract(AccountRef(common.HexToAddress("1337")),
nil, new(big.Int), p.RequiredGas(in)-1)
t.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(t *testing.T) {
_, err := RunPrecompiledContract(p, in, contract)
gas := p.RequiredGas(in) - 1

t.Run(fmt.Sprintf("%s-Gas=%d", test.name, gas), func(t *testing.T) {
_, _, err := RunPrecompiledContract(nil, p, in, gas)
if err.Error() != "out of gas" {
t.Errorf("Expected error [out of gas], got [%v]", err)
}
Expand All @@ -574,11 +556,9 @@ func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing.T) {
p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
in := common.Hex2Bytes(test.input)
contract := NewContract(AccountRef(common.HexToAddress("31337")),
nil, new(big.Int), p.RequiredGas(in))

gas := p.RequiredGas(in)
t.Run(test.name, func(t *testing.T) {
_, err := RunPrecompiledContract(p, in, contract)
_, _, err := RunPrecompiledContract(nil, p, in, gas)
if !reflect.DeepEqual(err, test.expectedError) {
t.Errorf("Expected error [%v], got [%v]", test.expectedError, err)
}
Expand All @@ -597,21 +577,18 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
in := common.Hex2Bytes(test.input)
reqGas := p.RequiredGas(in)
contract := NewContract(AccountRef(common.HexToAddress("1337")),
nil, new(big.Int), reqGas)

var (
res []byte
err error
data = make([]byte, len(in))
)

bench.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(bench *testing.B) {
bench.Run(fmt.Sprintf("%s-Gas=%d", test.name, reqGas), func(bench *testing.B) {
bench.ResetTimer()
for i := 0; i < bench.N; i++ {
contract.Gas = reqGas
copy(data, in)
res, err = RunPrecompiledContract(p, data, contract)
res, _, err = RunPrecompiledContract(nil, p, data, reqGas)
}
bench.StopTimer()
//Check if it is correct
Expand Down
Loading

0 comments on commit a92e0be

Please sign in to comment.