Skip to content

Commit 268d950

Browse files
authored
core/vm: change Consortium precompiled mapping into global variable (#461)
* core/vm: add tests for precompile query * core/vm: change Consortium precompiled mapping into global variable precompile query is a hot function which is called in every call related opcode. This commit tries to optimize this function by making the Consortium precompiled contract mapping into global variable so that precompile query does not need to dynamically allocate the mapping every time it is called. > go test -bench=BenchmarkConsortiumPrecompileQuery -benchtime=5s -tags=blst_enabled Before: goos: linux goarch: amd64 pkg: github.com/ethereum/go-ethereum/core/vm cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz BenchmarkConsortiumPrecompileQuery-8 4216357 2402 ns/op 1166 B/op 9 allocs/op After: goos: linux goarch: amd64 pkg: github.com/ethereum/go-ethereum/core/vm cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz BenchmarkConsortiumPrecompileQuery-8 100000000 50.40 ns/op 24 B/op 1 allocs/op
1 parent 5768525 commit 268d950

File tree

5 files changed

+196
-91
lines changed

5 files changed

+196
-91
lines changed

core/vm/consortium_precompiled_contracts.go

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,24 +84,16 @@ func init() {
8484
}
8585
}
8686

87-
func PrecompiledContractsConsortium(caller ContractRef, evm *EVM) map[common.Address]PrecompiledContract {
88-
return map[common.Address]PrecompiledContract{
89-
common.BytesToAddress([]byte{101}): &consortiumLog{},
90-
common.BytesToAddress([]byte{102}): &consortiumValidatorSorting{caller: caller, evm: evm},
91-
common.BytesToAddress([]byte{103}): &consortiumVerifyHeaders{caller: caller, evm: evm},
92-
common.BytesToAddress([]byte{104}): &consortiumPickValidatorSet{caller: caller, evm: evm},
93-
common.BytesToAddress([]byte{105}): &consortiumValidateFinalityProof{caller: caller, evm: evm},
94-
}
95-
}
96-
97-
func PrecompiledContractsConsortiumMiko(caller ContractRef, evm *EVM) map[common.Address]PrecompiledContract {
98-
contracts := PrecompiledContractsConsortium(caller, evm)
99-
contracts[common.BytesToAddress([]byte{106})] = &consortiumValidateProofOfPossession{caller: caller, evm: evm}
100-
return contracts
87+
type PrecompiledContractWithInit interface {
88+
PrecompiledContract
89+
Init(caller ContractRef, evm *EVM)
10190
}
10291

10392
type consortiumLog struct{}
10493

94+
func (c *consortiumLog) Init(_ ContractRef, _ *EVM) {
95+
}
96+
10597
func (c *consortiumLog) RequiredGas(_ []byte) uint64 {
10698
return 0
10799
}
@@ -145,6 +137,11 @@ type consortiumPickValidatorSet struct {
145137
evm *EVM
146138
}
147139

140+
func (c *consortiumPickValidatorSet) Init(caller ContractRef, evm *EVM) {
141+
c.caller = caller
142+
c.evm = evm
143+
}
144+
148145
func (c *consortiumPickValidatorSet) RequiredGas(input []byte) uint64 {
149146
// c.evm is nil in benchmark
150147
if c.evm == nil || c.evm.chainRules.IsMiko {
@@ -278,6 +275,11 @@ type consortiumValidatorSorting struct {
278275
evm *EVM
279276
}
280277

278+
func (c *consortiumValidatorSorting) Init(caller ContractRef, evm *EVM) {
279+
c.caller = caller
280+
c.evm = evm
281+
}
282+
281283
func (c *consortiumValidatorSorting) RequiredGas(input []byte) uint64 {
282284
// c.evm is nil in benchmark
283285
if c.evm == nil || c.evm.chainRules.IsMiko {
@@ -435,6 +437,11 @@ type consortiumVerifyHeaders struct {
435437
test bool
436438
}
437439

440+
func (c *consortiumVerifyHeaders) Init(caller ContractRef, evm *EVM) {
441+
c.caller = caller
442+
c.evm = evm
443+
}
444+
438445
func (c *consortiumVerifyHeaders) RequiredGas(_ []byte) uint64 {
439446
// c.evm is nil in benchmark
440447
if c.evm == nil || c.evm.chainRules.IsMiko {
@@ -616,6 +623,11 @@ type consortiumValidateFinalityProof struct {
616623
evm *EVM
617624
}
618625

626+
func (c *consortiumValidateFinalityProof) Init(caller ContractRef, evm *EVM) {
627+
c.caller = caller
628+
c.evm = evm
629+
}
630+
619631
func (contract *consortiumValidateFinalityProof) RequiredGas(input []byte) uint64 {
620632
return params.ValidateFinalityProofGas
621633
}
@@ -728,6 +740,11 @@ type consortiumValidateProofOfPossession struct {
728740
evm *EVM
729741
}
730742

743+
func (c *consortiumValidateProofOfPossession) Init(caller ContractRef, evm *EVM) {
744+
c.caller = caller
745+
c.evm = evm
746+
}
747+
731748
func (contract *consortiumValidateProofOfPossession) RequiredGas(input []byte) uint64 {
732749
return params.ValidateProofOfPossession
733750
}

core/vm/consortium_precompiled_contracts_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1840,7 +1840,7 @@ func newEVM(caller common.Address, statedb StateDB) (*EVM, error) {
18401840
},
18411841
chainConfig: params.TestChainConfig,
18421842
StateDB: statedb,
1843-
chainRules: params.Rules{IsIstanbul: true, IsEIP150: true},
1843+
chainRules: params.Rules{IsIstanbul: true, IsEIP150: true, IsConsortiumV2: true},
18441844
}
18451845
evm.chainConfig.ConsortiumV2Block = common.Big1
18461846
evm.interpreter = NewEVMInterpreter(evm, Config{NoBaseFee: true})

core/vm/contracts.go

Lines changed: 81 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ import (
2020
"crypto/sha256"
2121
"encoding/binary"
2222
"errors"
23+
"math/big"
24+
2325
"github.com/ethereum/go-ethereum/common"
2426
"github.com/ethereum/go-ethereum/common/math"
2527
"github.com/ethereum/go-ethereum/crypto"
2628
"github.com/ethereum/go-ethereum/crypto/blake2b"
2729
"github.com/ethereum/go-ethereum/crypto/bls12381"
2830
"github.com/ethereum/go-ethereum/crypto/bn256"
2931
"github.com/ethereum/go-ethereum/params"
30-
"math/big"
3132

3233
//lint:ignore SA1019 Needed for precompile
3334
"golang.org/x/crypto/ripemd160"
@@ -41,56 +42,6 @@ type PrecompiledContract interface {
4142
Run(input []byte) ([]byte, error) // Run runs the precompiled contract
4243
}
4344

44-
// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
45-
// contracts used in the Frontier and Homestead releases.
46-
var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
47-
common.BytesToAddress([]byte{1}): &ecrecover{},
48-
common.BytesToAddress([]byte{2}): &sha256hash{},
49-
common.BytesToAddress([]byte{3}): &ripemd160hash{},
50-
common.BytesToAddress([]byte{4}): &dataCopy{},
51-
}
52-
53-
// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
54-
// contracts used in the Byzantium release.
55-
var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
56-
common.BytesToAddress([]byte{1}): &ecrecover{},
57-
common.BytesToAddress([]byte{2}): &sha256hash{},
58-
common.BytesToAddress([]byte{3}): &ripemd160hash{},
59-
common.BytesToAddress([]byte{4}): &dataCopy{},
60-
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false},
61-
common.BytesToAddress([]byte{6}): &bn256AddByzantium{},
62-
common.BytesToAddress([]byte{7}): &bn256ScalarMulByzantium{},
63-
common.BytesToAddress([]byte{8}): &bn256PairingByzantium{},
64-
}
65-
66-
// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum
67-
// contracts used in the Istanbul release.
68-
var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
69-
common.BytesToAddress([]byte{1}): &ecrecover{},
70-
common.BytesToAddress([]byte{2}): &sha256hash{},
71-
common.BytesToAddress([]byte{3}): &ripemd160hash{},
72-
common.BytesToAddress([]byte{4}): &dataCopy{},
73-
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false},
74-
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
75-
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
76-
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
77-
common.BytesToAddress([]byte{9}): &blake2F{},
78-
}
79-
80-
// PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum
81-
// contracts used in the Berlin release.
82-
var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{
83-
common.BytesToAddress([]byte{1}): &ecrecover{},
84-
common.BytesToAddress([]byte{2}): &sha256hash{},
85-
common.BytesToAddress([]byte{3}): &ripemd160hash{},
86-
common.BytesToAddress([]byte{4}): &dataCopy{},
87-
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
88-
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
89-
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
90-
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
91-
common.BytesToAddress([]byte{9}): &blake2F{},
92-
}
93-
9445
// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
9546
// contracts specified in EIP-2537. These are exported for testing purposes.
9647
var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
@@ -106,13 +57,78 @@ var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
10657
}
10758

10859
var (
109-
PrecompiledAddressesBerlin []common.Address
110-
PrecompiledAddressesIstanbul []common.Address
111-
PrecompiledAddressesByzantium []common.Address
112-
PrecompiledAddressesHomestead []common.Address
60+
PrecompiledAddressesBerlin []common.Address
61+
PrecompiledAddressesMiko []common.Address
62+
PrecompiledAddressesConsortium []common.Address
63+
PrecompiledAddressesIstanbul []common.Address
64+
PrecompiledAddressesByzantium []common.Address
65+
PrecompiledAddressesHomestead []common.Address
66+
67+
// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
68+
// contracts used in the Frontier and Homestead releases.
69+
PrecompiledContractsHomestead map[common.Address]PrecompiledContract
70+
71+
// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
72+
// contracts used in the Byzantium release.
73+
PrecompiledContractsByzantium map[common.Address]PrecompiledContract
74+
75+
// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum
76+
// contracts used in the Istanbul release.
77+
PrecompiledContractsIstanbul map[common.Address]PrecompiledContract
78+
79+
// PrecompiledContractsConsortium contains additional Consortium precompiled contract
80+
// beside PrecompiledContractsIstanbul
81+
PrecompiledContractsConsortium map[common.Address]PrecompiledContract
82+
83+
// PrecompiledContractsConsortium contains proof of possession precompiled contract
84+
// beside PrecompiledContractsConsortium
85+
PrecompiledContractsConsortiumMiko map[common.Address]PrecompiledContract
86+
87+
// PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum
88+
// contracts used in the Berlin release.
89+
PrecompiledContractsBerlin map[common.Address]PrecompiledContract
11390
)
11491

92+
func copyPrecompiledContract(contracts map[common.Address]PrecompiledContract) map[common.Address]PrecompiledContract {
93+
cpy := make(map[common.Address]PrecompiledContract)
94+
95+
for address, contract := range contracts {
96+
cpy[address] = contract
97+
}
98+
99+
return cpy
100+
}
101+
115102
func init() {
103+
PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
104+
common.BytesToAddress([]byte{1}): &ecrecover{},
105+
common.BytesToAddress([]byte{2}): &sha256hash{},
106+
common.BytesToAddress([]byte{3}): &ripemd160hash{},
107+
common.BytesToAddress([]byte{4}): &dataCopy{},
108+
}
109+
110+
PrecompiledContractsByzantium = copyPrecompiledContract(PrecompiledContractsHomestead)
111+
PrecompiledContractsByzantium[common.BytesToAddress([]byte{5})] = &bigModExp{eip2565: false}
112+
PrecompiledContractsByzantium[common.BytesToAddress([]byte{6})] = &bn256AddByzantium{}
113+
PrecompiledContractsByzantium[common.BytesToAddress([]byte{7})] = &bn256ScalarMulByzantium{}
114+
PrecompiledContractsByzantium[common.BytesToAddress([]byte{8})] = &bn256PairingByzantium{}
115+
116+
PrecompiledContractsIstanbul = copyPrecompiledContract(PrecompiledContractsByzantium)
117+
PrecompiledContractsIstanbul[common.BytesToAddress([]byte{9})] = &blake2F{}
118+
119+
PrecompiledContractsConsortium = copyPrecompiledContract(PrecompiledContractsIstanbul)
120+
PrecompiledContractsConsortium[common.BytesToAddress([]byte{101})] = &consortiumLog{}
121+
PrecompiledContractsConsortium[common.BytesToAddress([]byte{102})] = &consortiumValidatorSorting{}
122+
PrecompiledContractsConsortium[common.BytesToAddress([]byte{103})] = &consortiumVerifyHeaders{}
123+
PrecompiledContractsConsortium[common.BytesToAddress([]byte{104})] = &consortiumPickValidatorSet{}
124+
PrecompiledContractsConsortium[common.BytesToAddress([]byte{105})] = &consortiumValidateFinalityProof{}
125+
126+
PrecompiledContractsConsortiumMiko = copyPrecompiledContract(PrecompiledContractsConsortium)
127+
PrecompiledContractsConsortiumMiko[common.BytesToAddress([]byte{106})] = &consortiumValidateProofOfPossession{}
128+
129+
PrecompiledContractsBerlin = copyPrecompiledContract(PrecompiledContractsConsortiumMiko)
130+
PrecompiledContractsBerlin[common.BytesToAddress([]byte{5})] = &bigModExp{eip2565: true}
131+
116132
for k := range PrecompiledContractsHomestead {
117133
PrecompiledAddressesHomestead = append(PrecompiledAddressesHomestead, k)
118134
}
@@ -122,6 +138,12 @@ func init() {
122138
for k := range PrecompiledContractsIstanbul {
123139
PrecompiledAddressesIstanbul = append(PrecompiledAddressesIstanbul, k)
124140
}
141+
for k := range PrecompiledContractsConsortium {
142+
PrecompiledAddressesConsortium = append(PrecompiledAddressesConsortium, k)
143+
}
144+
for k := range PrecompiledContractsConsortiumMiko {
145+
PrecompiledAddressesMiko = append(PrecompiledAddressesMiko, k)
146+
}
125147
for k := range PrecompiledContractsBerlin {
126148
PrecompiledAddressesBerlin = append(PrecompiledAddressesBerlin, k)
127149
}
@@ -132,6 +154,10 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
132154
switch {
133155
case rules.IsBerlin:
134156
return PrecompiledAddressesBerlin
157+
case rules.IsMiko:
158+
return PrecompiledAddressesMiko
159+
case rules.IsConsortiumV2:
160+
return PrecompiledAddressesConsortium
135161
case rules.IsIstanbul:
136162
return PrecompiledAddressesIstanbul
137163
case rules.IsByzantium:

core/vm/evm.go

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -67,36 +67,29 @@ func (evm *EVM) precompile(caller ContractRef, addr common.Address) (Precompiled
6767
return &blacklistedAddress{}, true
6868
}
6969

70-
var tmpPrecompiles map[common.Address]PrecompiledContract
71-
// add eth precompile contracts
70+
var precompiles map[common.Address]PrecompiledContract
7271
switch {
7372
case evm.chainRules.IsBerlin:
74-
tmpPrecompiles = PrecompiledContractsBerlin
73+
precompiles = PrecompiledContractsBerlin
74+
case evm.chainRules.IsMiko:
75+
precompiles = PrecompiledContractsConsortiumMiko
76+
case evm.chainRules.IsConsortiumV2:
77+
precompiles = PrecompiledContractsConsortium
7578
case evm.chainRules.IsIstanbul:
76-
tmpPrecompiles = PrecompiledContractsIstanbul
79+
precompiles = PrecompiledContractsIstanbul
7780
case evm.chainRules.IsByzantium:
78-
tmpPrecompiles = PrecompiledContractsByzantium
81+
precompiles = PrecompiledContractsByzantium
7982
default:
80-
tmpPrecompiles = PrecompiledContractsHomestead
83+
precompiles = PrecompiledContractsHomestead
8184
}
8285

83-
precompiles := make(map[common.Address]PrecompiledContract)
84-
for address, contract := range tmpPrecompiles {
85-
precompiles[address] = contract
86-
}
87-
88-
// add consortium precompiled contracts to list
89-
var consortiumContracts map[common.Address]PrecompiledContract
90-
if evm.chainRules.IsMiko {
91-
consortiumContracts = PrecompiledContractsConsortiumMiko(caller, evm)
92-
} else {
93-
consortiumContracts = PrecompiledContractsConsortium(caller, evm)
94-
}
95-
for address, contract := range consortiumContracts {
96-
precompiles[address] = contract
86+
p, ok := precompiles[addr]
87+
if ok {
88+
if pWithInit, hasInit := p.(PrecompiledContractWithInit); hasInit {
89+
pWithInit.Init(caller, evm)
90+
}
9791
}
9892

99-
p, ok := precompiles[addr]
10093
return p, ok
10194
}
10295

0 commit comments

Comments
 (0)