From 265bf110a20edab8abfebc15c71879eda55cdb82 Mon Sep 17 00:00:00 2001 From: minh-bq <97180373+minh-bq@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:18:13 +0700 Subject: [PATCH] core/state: reduce memory allocation in IsAddressBlacklisted (#460) * core/state: add GetLocMappingAtKey test * core/state: reduce memory allocation in GetLocMappingAtKey > go test -bench=BenchmarkGetLocMappingAtKey -benchtime=5s Before goos: linux goarch: amd64 pkg: github.com/ethereum/go-ethereum/core/state cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz BenchmarkGetLocMappingAtKey-8 8499260 877.7 ns/op 664 B/op 9 allocs/op After goos: linux goarch: amd64 pkg: github.com/ethereum/go-ethereum/core/state cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz BenchmarkGetLocMappingAtKey-8 9745719 592.2 ns/op 584 B/op 5 allocs/op * core/state: add IsAddressBlacklisted test * core/state: reduce memory allocation in IsAddressBlacklisted > go test -bench=BenchmarkIsAddressBlacklisted -benchtime=5s Before goos: linux goarch: amd64 pkg: github.com/ethereum/go-ethereum/core/state cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz BenchmarkIsAddressBlacklisted-8 3349110 2432 ns/op 480 B/op 11 allocs/op After goos: linux goarch: amd64 pkg: github.com/ethereum/go-ethereum/core/state cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz BenchmarkIsAddressBlacklisted-8 3863929 2245 ns/op 352 B/op 9 allocs/op * core/state: reduce memory allocation in GetLocSimpleVariable --- core/state/location_cacl.go | 18 ++++++++---- core/state/location_cacl_test.go | 33 +++++++++++++++++++++ core/state/statedb_utils.go | 14 ++++++--- core/state/statedb_utils_test.go | 49 ++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 core/state/location_cacl_test.go create mode 100644 core/state/statedb_utils_test.go diff --git a/core/state/location_cacl.go b/core/state/location_cacl.go index 77c70f02ef..50b092a6bb 100644 --- a/core/state/location_cacl.go +++ b/core/state/location_cacl.go @@ -1,6 +1,7 @@ package state import ( + "encoding/binary" "math/big" "github.com/ethereum/go-ethereum/common" @@ -8,16 +9,21 @@ import ( ) func GetLocSimpleVariable(slot uint64) common.Hash { - slotHash := common.BigToHash(new(big.Int).SetUint64(slot)) + var slotHash common.Hash + + binary.BigEndian.PutUint64(slotHash[len(slotHash)-8:], slot) return slotHash } func GetLocMappingAtKey(key common.Hash, slot uint64) common.Hash { - slotHash := common.BigToHash(new(big.Int).SetUint64(slot)) - retByte := crypto.Keccak256(key.Bytes(), slotHash.Bytes()) - ret := new(big.Int) - ret.SetBytes(retByte) - return common.BigToHash(ret) + var buffer []byte + + buffer = key.Bytes() + // Write 8-byte slot to 32-byte space in big endian order. + // First write 24 0-bytes then write 8-slot in big endian. + buffer = common.PadTo(buffer, len(buffer)+24) + buffer = binary.BigEndian.AppendUint64(buffer, slot) + return crypto.Keccak256Hash(buffer) } func GetLocDynamicArrAtElement(slotHash common.Hash, index uint64, elementSize uint64) common.Hash { diff --git a/core/state/location_cacl_test.go b/core/state/location_cacl_test.go new file mode 100644 index 0000000000..39057b691a --- /dev/null +++ b/core/state/location_cacl_test.go @@ -0,0 +1,33 @@ +package state + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +func TestGetLocSimpleVariable(t *testing.T) { + hash := GetLocSimpleVariable(12) + expect := common.BigToHash(big.NewInt(12)) + + if hash != expect { + t.Fatalf("Hash mismatches, got %s expect %s", hash, expect) + } +} + +func TestGetLocMappingAtKey(t *testing.T) { + hash := GetLocMappingAtKey(common.BigToHash(big.NewInt(10)), 12) + + expect := common.HexToHash("0x9e6c92d7be355807bd948171438a5e65aaf9e4c36f1405c1b9ca25d27c4ea3a0") + if hash != expect { + t.Fatalf("Hash mismatches, got %s expect %s", hash, expect) + } +} + +func BenchmarkGetLocMappingAtKey(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + GetLocMappingAtKey(common.BigToHash(big.NewInt(10)), 12) + } +} diff --git a/core/state/statedb_utils.go b/core/state/statedb_utils.go index e74bef9786..1f6f358483 100644 --- a/core/state/statedb_utils.go +++ b/core/state/statedb_utils.go @@ -34,8 +34,13 @@ var ( slotRoninValidatorMapping = map[string]uint64{ VALIDATORS: 6, } + valueOne common.Hash ) +func init() { + valueOne.SetBytes([]byte{0x1}) +} + // IsWhitelistedDeployer reads the contract storage to check if an address is allow to deploy func IsWhitelistedDeployerV2(statedb *StateDB, address common.Address, blockTime uint64, whiteListContract *common.Address) bool { contract := *whiteListContract @@ -94,15 +99,16 @@ func IsAddressBlacklisted(statedb *StateDB, blacklistAddr *common.Address, addre contract := *blacklistAddr disabledSlot := slotBlacklistContractMapping[DISABLED] - disabled := statedb.GetState(contract, GetLocSimpleVariable(disabledSlot)) - if disabled.Big().Cmp(big.NewInt(1)) == 0 { + disabledStateValue := statedb.GetState(contract, GetLocSimpleVariable(disabledSlot)) + + if disabledStateValue == valueOne { return false } blacklistedSlot := slotBlacklistContractMapping[BLACKLISTED] valueLoc := GetLocMappingAtKey(address.Hash(), blacklistedSlot) - blacklisted := statedb.GetState(contract, valueLoc) - return blacklisted.Big().Cmp(big.NewInt(1)) == 0 + blacklistedStateValue := statedb.GetState(contract, valueLoc) + return blacklistedStateValue == valueOne } func GetSCValidators(statedb *StateDB) []common.Address { diff --git a/core/state/statedb_utils_test.go b/core/state/statedb_utils_test.go new file mode 100644 index 0000000000..8344736f00 --- /dev/null +++ b/core/state/statedb_utils_test.go @@ -0,0 +1,49 @@ +package state + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" +) + +func TestIsAddressBlacklisted(t *testing.T) { + blackListContract := common.Address{0x11} + + statedb, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) + + blacklistedAddress := common.BigToAddress(common.Big3) + // Blacklist address 0x000..0003 + statedb.SetState( + blackListContract, + common.HexToHash("0x7dfe757ecd65cbd7922a9c0161e935dd7fdbcc0e999689c7d31633896b1fc60b"), + common.BigToHash(common.Big1), + ) + if !IsAddressBlacklisted(statedb, &blackListContract, &blacklistedAddress) { + t.Fatalf("Expect address %s to be blacklisted", blacklistedAddress.String()) + } + + notBlacklistedAddress := common.BigToAddress(big.NewInt(10)) + if IsAddressBlacklisted(statedb, &blackListContract, ¬BlacklistedAddress) { + t.Fatalf("Expect address %s to be not blacklisted", notBlacklistedAddress.String()) + } + + statedb.SetState(blackListContract, common.BigToHash(common.Big2), common.BigToHash(common.Big1)) + if IsAddressBlacklisted(statedb, &blackListContract, &blacklistedAddress) { + t.Fatalf("Expect address %s to be not blacklisted", blacklistedAddress.String()) + } +} + +func BenchmarkIsAddressBlacklisted(b *testing.B) { + statedb, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) + blackListContract := common.Address{0x11} + + queriedAddress := common.BigToAddress(common.Big3) + + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + IsAddressBlacklisted(statedb, &blackListContract, &queriedAddress) + } +}