From 18cb67bdbfe4948564b2d0c660cb2d709d94e3de Mon Sep 17 00:00:00 2001 From: emailtovamos Date: Tue, 23 Apr 2024 06:39:15 +0100 Subject: [PATCH 1/7] metrics: add doublesign counter --- core/vm/contracts.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 5749682f3b..a08b97058a 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" ) @@ -276,6 +277,10 @@ var ( PrecompiledAddressesHomestead []common.Address ) +var ( + doubleSignCounter = metrics.NewRegisteredCounter("vm/contracts/doublesign", nil) +) + func init() { for k := range PrecompiledContractsHomestead { PrecompiledAddressesHomestead = append(PrecompiledAddressesHomestead, k) @@ -1478,5 +1483,7 @@ func (c *verifyDoubleSignEvidence) Run(input []byte) ([]byte, error) { copy(returnBz[:20], signerAddr) copy(returnBz[52-len(evidenceHeightBz):], evidenceHeightBz) + doubleSignCounter.Inc(1) + return returnBz, nil } From 216013b4b336f15613d2b84bfc522ee860e15226 Mon Sep 17 00:00:00 2001 From: emailtovamos Date: Fri, 26 Apr 2024 09:16:59 +0100 Subject: [PATCH 2/7] metrics: add metrics for double sign --- consensus/parlia/parlia.go | 35 +++++++++++++++++++++++++++++++++-- core/vm/contracts.go | 7 ------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 063a733c35..fa4e074ae7 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -10,6 +10,7 @@ import ( "math/big" "math/rand" "sort" + "strconv" "strings" "sync" "time" @@ -80,6 +81,7 @@ var ( verifyVoteAttestationErrorCounter = metrics.NewRegisteredCounter("parlia/verifyVoteAttestation/error", nil) updateAttestationErrorCounter = metrics.NewRegisteredCounter("parlia/updateAttestation/error", nil) validVotesfromSelfCounter = metrics.NewRegisteredCounter("parlia/VerifyVote/self", nil) + doubleSignCounter = metrics.NewRegisteredCounter("parlia/doublesign", nil) systemContracts = map[common.Address]bool{ common.HexToAddress(systemcontracts.ValidatorContract): true, @@ -216,8 +218,11 @@ type Parlia struct { genesisHash common.Hash db ethdb.Database // Database to store and retrieve snapshot checkpoints - recentSnaps *lru.ARCCache // Snapshots for recent block to speed up - signatures *lru.ARCCache // Signatures of recent blocks to speed up mining + recentSnaps *lru.ARCCache // Snapshots for recent block to speed up + signatures *lru.ARCCache // Signatures of recent blocks to speed up mining + recentHeadersMap map[string]types.Header + // Recent headers to check for double signing: key includes block number and miner. value is the block header + // If same key's value already exists for different block header roots then double sign is detected signer types.Signer @@ -263,6 +268,7 @@ func New( if err != nil { panic(err) } + recentHeadersMap := make(map[string]types.Header) vABIBeforeLuban, err := abi.JSON(strings.NewReader(validatorSetABIBeforeLuban)) if err != nil { panic(err) @@ -286,6 +292,7 @@ func New( db: db, ethAPI: ethAPI, recentSnaps: recentSnaps, + recentHeadersMap: recentHeadersMap, signatures: signatures, validatorSetABIBeforeLuban: vABIBeforeLuban, validatorSetABI: vABI, @@ -813,6 +820,14 @@ func (p *Parlia) verifySeal(chain consensus.ChainHeaderReader, header *types.Hea return errUnauthorizedValidator(signer.String()) } + // todo check for double sign & add to cache + key := proposalKey(*header) + value, ok := p.recentHeadersMap[key] + if ok { + doubleSignCounter.Inc(1) + } + p.recentHeadersMap[key] = value + if snap.SignRecently(signer) { return errRecentlySigned } @@ -2011,3 +2026,19 @@ func applyMessage( } return msg.Gas() - returnGas, err } + +// proposalKey build a key which is a combination of the slot and the proposer index. +// If a validator proposes several blocks for the same slot, then several (potentially slashable) +// proposals will correspond to the same key. +func proposalKey(header types.Header) string { + + slotKey := uintToString(header.Number.Uint64()) + proposerIndexKey := uintToString(header.Coinbase.Big().Uint64()) + + return slotKey + ":" + proposerIndexKey +} + +// Turns a uint64 value to a string representation. +func uintToString(val uint64) string { + return strconv.FormatUint(val, 10) +} diff --git a/core/vm/contracts.go b/core/vm/contracts.go index a08b97058a..5749682f3b 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -37,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" ) @@ -277,10 +276,6 @@ var ( PrecompiledAddressesHomestead []common.Address ) -var ( - doubleSignCounter = metrics.NewRegisteredCounter("vm/contracts/doublesign", nil) -) - func init() { for k := range PrecompiledContractsHomestead { PrecompiledAddressesHomestead = append(PrecompiledAddressesHomestead, k) @@ -1483,7 +1478,5 @@ func (c *verifyDoubleSignEvidence) Run(input []byte) ([]byte, error) { copy(returnBz[:20], signerAddr) copy(returnBz[52-len(evidenceHeightBz):], evidenceHeightBz) - doubleSignCounter.Inc(1) - return returnBz, nil } From d7e974adee62c0bdad5a63a0a27dd559e5db6ff2 Mon Sep 17 00:00:00 2001 From: emailtovamos Date: Fri, 26 Apr 2024 09:28:36 +0100 Subject: [PATCH 3/7] metrics: use cache instead of map --- consensus/parlia/parlia.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index fa4e074ae7..992217254d 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -218,9 +218,9 @@ type Parlia struct { genesisHash common.Hash db ethdb.Database // Database to store and retrieve snapshot checkpoints - recentSnaps *lru.ARCCache // Snapshots for recent block to speed up - signatures *lru.ARCCache // Signatures of recent blocks to speed up mining - recentHeadersMap map[string]types.Header + recentSnaps *lru.ARCCache // Snapshots for recent block to speed up + signatures *lru.ARCCache // Signatures of recent blocks to speed up mining + recentHeaders *lru.ARCCache // // Recent headers to check for double signing: key includes block number and miner. value is the block header // If same key's value already exists for different block header roots then double sign is detected @@ -268,7 +268,10 @@ func New( if err != nil { panic(err) } - recentHeadersMap := make(map[string]types.Header) + recentHeaders, err := lru.NewARC(inMemorySignatures) + if err != nil { + panic(err) + } vABIBeforeLuban, err := abi.JSON(strings.NewReader(validatorSetABIBeforeLuban)) if err != nil { panic(err) @@ -292,7 +295,7 @@ func New( db: db, ethAPI: ethAPI, recentSnaps: recentSnaps, - recentHeadersMap: recentHeadersMap, + recentHeaders: recentHeaders, signatures: signatures, validatorSetABIBeforeLuban: vABIBeforeLuban, validatorSetABI: vABI, @@ -820,13 +823,15 @@ func (p *Parlia) verifySeal(chain consensus.ChainHeaderReader, header *types.Hea return errUnauthorizedValidator(signer.String()) } - // todo check for double sign & add to cache + // check for double sign & add to cache key := proposalKey(*header) - value, ok := p.recentHeadersMap[key] + + value, ok := p.recentHeaders.Get(key) if ok { doubleSignCounter.Inc(1) + } else { + p.recentHeaders.Add(key, value) } - p.recentHeadersMap[key] = value if snap.SignRecently(signer) { return errRecentlySigned From bc78ef819584b59df2becef5199a20301a43f3c7 Mon Sep 17 00:00:00 2001 From: emailtovamos Date: Fri, 26 Apr 2024 09:34:06 +0100 Subject: [PATCH 4/7] metrics: comments --- consensus/parlia/parlia.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 992217254d..a3daa576a7 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -2032,9 +2032,7 @@ func applyMessage( return msg.Gas() - returnGas, err } -// proposalKey build a key which is a combination of the slot and the proposer index. -// If a validator proposes several blocks for the same slot, then several (potentially slashable) -// proposals will correspond to the same key. +// proposalKey build a key which is a combination of the block number and the proposer address. func proposalKey(header types.Header) string { slotKey := uintToString(header.Number.Uint64()) From 295fcc540de480e3028be1e7ef4765541d992ca2 Mon Sep 17 00:00:00 2001 From: emailtovamos Date: Fri, 26 Apr 2024 09:55:03 +0100 Subject: [PATCH 5/7] metrics: remove unneeded function --- consensus/parlia/parlia.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index a3daa576a7..608c3be05c 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -10,7 +10,6 @@ import ( "math/big" "math/rand" "sort" - "strconv" "strings" "sync" "time" @@ -2035,13 +2034,8 @@ func applyMessage( // proposalKey build a key which is a combination of the block number and the proposer address. func proposalKey(header types.Header) string { - slotKey := uintToString(header.Number.Uint64()) - proposerIndexKey := uintToString(header.Coinbase.Big().Uint64()) + slotKey := header.Number.String() + proposerIndexKey := header.Coinbase.String() return slotKey + ":" + proposerIndexKey } - -// Turns a uint64 value to a string representation. -func uintToString(val uint64) string { - return strconv.FormatUint(val, 10) -} From 019eb3232b0f1693578661db7c7dfc2eb8726f06 Mon Sep 17 00:00:00 2001 From: emailtovamos Date: Fri, 26 Apr 2024 10:18:40 +0100 Subject: [PATCH 6/7] metrics: consider same blk instead of same height --- consensus/parlia/parlia.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 608c3be05c..4bdc4628a0 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -2033,9 +2033,5 @@ func applyMessage( // proposalKey build a key which is a combination of the block number and the proposer address. func proposalKey(header types.Header) string { - - slotKey := header.Number.String() - proposerIndexKey := header.Coinbase.String() - - return slotKey + ":" + proposerIndexKey + return header.ParentHash.String() + header.Coinbase.String() } From c13f627eed63303222b270bd52aea8929be4b2f4 Mon Sep 17 00:00:00 2001 From: emailtovamos Date: Fri, 26 Apr 2024 10:22:26 +0100 Subject: [PATCH 7/7] metrics: higher cache size --- consensus/parlia/parlia.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 4bdc4628a0..d015a7970d 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -48,8 +48,9 @@ import ( ) const ( - inMemorySnapshots = 256 // Number of recent snapshots to keep in memory - inMemorySignatures = 4096 // Number of recent block signatures to keep in memory + inMemorySnapshots = 256 // Number of recent snapshots to keep in memory + inMemorySignatures = 4096 // Number of recent block signatures to keep in memory + inMemoryHeaders = 86400 // Number of recent headers to keep in memory for double sign detection checkpointInterval = 1024 // Number of blocks after which to save the snapshot to the database defaultEpochLength = uint64(100) // Default number of blocks of checkpoint to update validatorSet from contract @@ -267,7 +268,7 @@ func New( if err != nil { panic(err) } - recentHeaders, err := lru.NewARC(inMemorySignatures) + recentHeaders, err := lru.NewARC(inMemoryHeaders) if err != nil { panic(err) }