1717package clique
1818
1919import (
20+ "bytes"
2021 "math/big"
22+ "strings"
2123 "testing"
2224
2325 "github.com/scroll-tech/go-ethereum/common"
@@ -27,6 +29,7 @@ import (
2729 "github.com/scroll-tech/go-ethereum/core/vm"
2830 "github.com/scroll-tech/go-ethereum/crypto"
2931 "github.com/scroll-tech/go-ethereum/params"
32+ "github.com/scroll-tech/go-ethereum/trie"
3033)
3134
3235// This test case is a repro of an annoying bug that took us forever to catch.
@@ -123,3 +126,91 @@ func TestSealHash(t *testing.T) {
123126 t .Errorf ("have %x, want %x" , have , want )
124127 }
125128}
129+
130+ func TestShadowFork (t * testing.T ) {
131+ engineConf := * params .AllCliqueProtocolChanges .Clique
132+ engineConf .Epoch = 2
133+ forkedEngineConf := engineConf
134+ forkedEngineConf .ShadowForkHeight = 3
135+ shadowForkKey , _ := crypto .HexToECDSA (strings .Repeat ("11" , 32 ))
136+ shadowForkAddr := crypto .PubkeyToAddress (shadowForkKey .PublicKey )
137+ forkedEngineConf .ShadowForkSigner = shadowForkAddr
138+
139+ // Initialize a Clique chain with a single signer
140+ var (
141+ db = rawdb .NewMemoryDatabase ()
142+ key , _ = crypto .HexToECDSA ("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" )
143+ addr = crypto .PubkeyToAddress (key .PublicKey )
144+ engine = New (& engineConf , db )
145+ signer = new (types.HomesteadSigner )
146+ forkedEngine = New (& forkedEngineConf , db )
147+ )
148+ genspec := & core.Genesis {
149+ Config : params .AllCliqueProtocolChanges ,
150+ ExtraData : make ([]byte , extraVanity + common .AddressLength + extraSeal ),
151+ Alloc : map [common.Address ]core.GenesisAccount {
152+ addr : {Balance : big .NewInt (10000000000000000 )},
153+ },
154+ BaseFee : big .NewInt (params .InitialBaseFee ),
155+ }
156+ copy (genspec .ExtraData [extraVanity :], addr [:])
157+ genesis := genspec .MustCommit (db , trie .NewDatabase (db , trie .HashDefaults ))
158+
159+ // Generate a batch of blocks, each properly signed
160+ chain , _ := core .NewBlockChain (db , nil , genspec , nil , engine , vm.Config {}, nil , nil )
161+ defer chain .Stop ()
162+
163+ forkedChain , _ := core .NewBlockChain (db , nil , genspec , nil , forkedEngine , vm.Config {}, nil , nil )
164+ defer forkedChain .Stop ()
165+
166+ blocks , _ := core .GenerateChain (params .AllCliqueProtocolChanges , genesis , forkedEngine , db , 16 , func (i int , block * core.BlockGen ) {
167+ // The chain maker doesn't have access to a chain, so the difficulty will be
168+ // lets unset (nil). Set it here to the correct value.
169+ if block .Number ().Uint64 () > forkedEngineConf .ShadowForkHeight {
170+ block .SetDifficulty (diffShadowFork )
171+ } else {
172+ block .SetDifficulty (diffInTurn )
173+ }
174+
175+ tx , err := types .SignTx (types .NewTransaction (block .TxNonce (addr ), common.Address {0x00 }, new (big.Int ), params .TxGas , block .BaseFee (), nil ), signer , key )
176+ if err != nil {
177+ panic (err )
178+ }
179+ block .AddTxWithChain (chain , tx )
180+ })
181+ for i , block := range blocks {
182+ header := block .Header ()
183+ if i > 0 {
184+ header .ParentHash = blocks [i - 1 ].Hash ()
185+ }
186+
187+ signingAddr , signingKey := addr , key
188+ if header .Number .Uint64 () > forkedEngineConf .ShadowForkHeight {
189+ // start signing with shadow fork authority key
190+ signingAddr , signingKey = shadowForkAddr , shadowForkKey
191+ }
192+
193+ header .Extra = make ([]byte , extraVanity )
194+ if header .Number .Uint64 ()% engineConf .Epoch == 0 {
195+ header .Extra = append (header .Extra , signingAddr .Bytes ()... )
196+ }
197+ header .Extra = append (header .Extra , bytes .Repeat ([]byte {0 }, extraSeal )... )
198+
199+ sig , _ := crypto .Sign (SealHash (header ).Bytes (), signingKey )
200+ copy (header .Extra [len (header .Extra )- extraSeal :], sig )
201+ blocks [i ] = block .WithSeal (header )
202+ }
203+
204+ if _ , err := chain .InsertChain (blocks ); err == nil {
205+ t .Fatalf ("should've failed to insert some blocks to canonical chain" )
206+ }
207+ if chain .CurrentHeader ().Number .Uint64 () != forkedEngineConf .ShadowForkHeight {
208+ t .Fatalf ("unexpected canonical chain height" )
209+ }
210+ if _ , err := forkedChain .InsertChain (blocks ); err != nil {
211+ t .Fatalf ("failed to insert blocks to forked chain: %v %d" , err , forkedChain .CurrentHeader ().Number )
212+ }
213+ if forkedChain .CurrentHeader ().Number .Uint64 () != uint64 (len (blocks )) {
214+ t .Fatalf ("unexpected forked chain height" )
215+ }
216+ }
0 commit comments