forked from ethereum/go-ethereum
-
Notifications
You must be signed in to change notification settings - Fork 283
feat: add system config consensus to deprecate clique #1102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 7 commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
b68dcb7
feat: add system config consensus to deprecate poa
yiweichi 8e4deb1
fix: check extra field lens
yiweichi a77524f
Finish implementation with one signer only
ranchalp 4047f24
Implement unit tests
ranchalp b68d2d6
Only check signature if block not requested
ranchalp ad96fa4
Remove Extra from rlp encoding (and hashing)
ranchalp ec2e3d0
Implement UpgradableEngine as middleware for Clique/SystemContract
ranchalp 20185f2
Use isEuclid, add json tag to Requested, make go idiomatic
ranchalp 4d00f42
Changes post integration test
ranchalp 9d8a128
Merge branch 'develop' into feat-system-config-consensus
ranchalp 80e06b8
Remove comment
ranchalp d4c725e
Address comments
ranchalp 8f961e7
Merge
ranchalp ebd8e61
New field BlockSignature (not used in hashing/JSON)
ranchalp c3f5b46
Enforce .Extra to be an empty slice
ranchalp 3190585
replace header.Requested for header.IsNewBlock
ranchalp 38135a3
mark new block as IsNewBlock
ranchalp d59e79b
Make new RLP optional fields always default for legacy/reth compatibi…
ranchalp b077f71
Placing new fields as last non-zero rlp:optional values used by Scroll
ranchalp 6b2a63b
Penalize nodes that send non-zero Euclid V2 header field values
ranchalp 3fa378d
Bring back .Requested to downloader instead of .IsNewBlock
ranchalp 6638057
Replace IsNewBlock for Requested
ranchalp cd6344d
Address comments
ranchalp f6bcdd0
merge
ranchalp 9ca7498
Merge branch 'develop' into feat-system-config-consensus
ranchalp 80eba61
prevent timing issues in tests
jonastheis b2fb9a2
fix ci
jonastheis 396db64
chore: auto version bump [bot]
jonastheis cc5c7dc
Update consensus/system_contract/consensus.go
ranchalp e70acc6
Merge branch 'develop' into feat-system-config-consensus
ranchalp b914e00
chore: auto version bump [bot]
ranchalp 0b00789
Update consensus/system_contract/consensus.go
ranchalp d1e4790
Remove whitespaces and merge version number
ranchalp 3839bf7
chore: auto version bump [bot]
ranchalp 3c2347e
validate that the read address from L1 is not empty and improved erro…
jonastheis 07559cb
Fix indentation issue
ranchalp 83bf259
Fix test
ranchalp 3151105
goimports fix
ranchalp 297186b
goimports
Thegaram File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jonastheis marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
package consensus_wrapper | ||
|
||
import ( | ||
"github.com/scroll-tech/go-ethereum/common" | ||
"github.com/scroll-tech/go-ethereum/consensus" | ||
"github.com/scroll-tech/go-ethereum/core/state" | ||
"github.com/scroll-tech/go-ethereum/core/types" | ||
"github.com/scroll-tech/go-ethereum/rpc" | ||
"math/big" | ||
"sync" | ||
) | ||
|
||
// UpgradableEngine implements consensus.Engine and acts as a middleware to dispatch | ||
// calls to either Clique or SystemContract consensus based on block height. | ||
type UpgradableEngine struct { | ||
// forkBlock is the block number at which the switchover to SystemContract occurs. | ||
forkBlock *big.Int | ||
|
||
// clique is the original Clique consensus engine. | ||
clique consensus.Engine | ||
|
||
// system is the new SystemContract consensus engine. | ||
system consensus.Engine | ||
} | ||
|
||
// NewUpgradableEngine constructs a new upgradable consensus middleware. | ||
func NewUpgradableEngine(forkBlock *big.Int, clique consensus.Engine, system consensus.Engine) *UpgradableEngine { | ||
return &UpgradableEngine{ | ||
forkBlock: forkBlock, | ||
clique: clique, | ||
system: system, | ||
} | ||
} | ||
|
||
// chooseEngine returns the appropriate consensus engine based on the header's number. | ||
func (ue *UpgradableEngine) chooseEngine(header *types.Header) consensus.Engine { | ||
jonastheis marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if header.Number == nil { | ||
// Fallback: treat as pre-fork if header number is unknown. | ||
return ue.clique | ||
} | ||
// If block number is >= forkBlock, use the new SystemContract consensus, else use Clique. | ||
if header.Number.Cmp(ue.forkBlock) >= 0 { | ||
return ue.system | ||
} | ||
return ue.clique | ||
} | ||
|
||
// -------------------- | ||
// Methods to implement consensus.Engine | ||
|
||
// Author returns the author of the block based on the header. | ||
func (ue *UpgradableEngine) Author(header *types.Header) (common.Address, error) { | ||
return ue.chooseEngine(header).Author(header) | ||
} | ||
|
||
// VerifyHeader checks whether a header conforms to the consensus rules of the engine. | ||
func (ue *UpgradableEngine) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error { | ||
return ue.chooseEngine(header).VerifyHeader(chain, header, seal) | ||
} | ||
|
||
// VerifyHeaders verifies a batch of headers concurrently. In our use-case, | ||
// headers can only be all system, all clique, or start with clique and then switch once to system. | ||
func (ue *UpgradableEngine) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { | ||
abort := make(chan struct{}) | ||
out := make(chan error) | ||
|
||
// If there are no headers, return a closed error channel. | ||
if len(headers) == 0 { | ||
close(out) | ||
return nil, out | ||
} | ||
|
||
// Choose engine for the first and last header. | ||
firstEngine := ue.chooseEngine(headers[0]) | ||
lastEngine := ue.chooseEngine(headers[len(headers)-1]) | ||
|
||
// If the first header is system, then all headers must be system. | ||
if firstEngine == ue.system { | ||
return firstEngine.VerifyHeaders(chain, headers, seals) | ||
} | ||
|
||
// If first and last headers are both clique, then all headers are clique. | ||
if firstEngine == lastEngine { | ||
return firstEngine.VerifyHeaders(chain, headers, seals) | ||
} | ||
|
||
// Otherwise, headers start as clique then switch to system. Since we assume | ||
// a single switchover, find the first header that uses system. | ||
splitIndex := 0 | ||
for i, header := range headers { | ||
if ue.chooseEngine(header) == ue.system { | ||
splitIndex = i | ||
break | ||
} | ||
} | ||
// It's expected that splitIndex is > 0. | ||
cliqueHeaders := headers[:splitIndex] | ||
cliqueSeals := seals[:splitIndex] | ||
systemHeaders := headers[splitIndex:] | ||
systemSeals := seals[splitIndex:] | ||
|
||
// Create a wait group to merge results. | ||
var wg sync.WaitGroup | ||
wg.Add(2) | ||
|
||
// Launch concurrent verifications. | ||
go func() { | ||
defer wg.Done() | ||
_, cliqueResults := ue.clique.VerifyHeaders(chain, cliqueHeaders, cliqueSeals) | ||
for err := range cliqueResults { | ||
select { | ||
case <-abort: | ||
return | ||
case out <- err: | ||
} | ||
} | ||
}() | ||
|
||
go func() { | ||
defer wg.Done() | ||
_, systemResults := ue.system.VerifyHeaders(chain, systemHeaders, systemSeals) | ||
for err := range systemResults { | ||
select { | ||
case <-abort: | ||
return | ||
case out <- err: | ||
} | ||
} | ||
}() | ||
|
||
// Close the out channel when both verifications are complete. | ||
go func() { | ||
wg.Wait() | ||
close(out) | ||
}() | ||
|
||
return abort, out | ||
} | ||
|
||
// Prepare prepares a block header for sealing. | ||
func (ue *UpgradableEngine) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { | ||
return ue.chooseEngine(header).Prepare(chain, header) | ||
} | ||
|
||
// Seal instructs the engine to start sealing a block. | ||
func (ue *UpgradableEngine) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { | ||
return ue.chooseEngine(block.Header()).Seal(chain, block, results, stop) | ||
} | ||
|
||
// CalcDifficulty calculates the block difficulty if applicable. | ||
func (ue *UpgradableEngine) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { | ||
return ue.chooseEngine(parent).CalcDifficulty(chain, time, parent) | ||
} | ||
|
||
// Finalize finalizes the block, applying any post-transaction rules. | ||
func (ue *UpgradableEngine) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { | ||
ue.chooseEngine(header).Finalize(chain, header, state, txs, uncles) | ||
} | ||
|
||
// FinalizeAndAssemble finalizes and assembles a new block. | ||
func (ue *UpgradableEngine) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { | ||
return ue.chooseEngine(header).FinalizeAndAssemble(chain, header, state, txs, uncles, receipts) | ||
} | ||
|
||
// VerifyUncles verifies that no uncles are attached to the block. | ||
func (ue *UpgradableEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { | ||
return ue.chooseEngine(block.Header()).VerifyUncles(chain, block) | ||
} | ||
|
||
// APIs returns any RPC APIs exposed by the consensus engine. | ||
func (ue *UpgradableEngine) APIs(chain consensus.ChainHeaderReader) []rpc.API { | ||
// Determine the current chain head. | ||
head := chain.CurrentHeader() | ||
if head == nil { | ||
// Fallback: return the clique APIs (or an empty slice) if we don't have a header. | ||
return ue.clique.APIs(chain) | ||
} | ||
|
||
// Choose engine based on whether the chain head is before or after the fork block. | ||
if head.Number.Cmp(ue.forkBlock) >= 0 { | ||
return ue.system.APIs(chain) | ||
} | ||
return ue.clique.APIs(chain) | ||
} | ||
|
||
// Close terminates the consensus engine. | ||
func (ue *UpgradableEngine) Close() error { | ||
// Always close both engines. | ||
if err := ue.clique.Close(); err != nil { | ||
return err | ||
} | ||
return ue.system.Close() | ||
} | ||
|
||
// SealHash returns the hash of a block prior to it being sealed. | ||
func (ue *UpgradableEngine) SealHash(header *types.Header) common.Hash { | ||
return ue.chooseEngine(header).SealHash(header) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package system_contract | ||
|
||
import ( | ||
"github.com/scroll-tech/go-ethereum/common" | ||
"github.com/scroll-tech/go-ethereum/consensus" | ||
"github.com/scroll-tech/go-ethereum/rpc" | ||
) | ||
|
||
// API is a user facing RPC API to allow controlling the signer and voting | ||
// mechanisms of the proof-of-authority scheme. | ||
type API struct { | ||
chain consensus.ChainHeaderReader | ||
} | ||
|
||
// GetSigners retrieves the list of authorized signers at the specified block. | ||
func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) { | ||
return nil, nil | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.