The
Portal still selects the Seal method, which is consistent with the previous parsing of the Ethash algorithm, since they are seal different implementations.
Our comments can be compared to see that the purpose of the Clique seal function is to try to create a sealed block by means of a local signature authentication (power signature and authentication, and finding a power node). Func (c *clique) Seal (chain consensus. Chainreader, Block *types. block, stop <-chan struct{}) (*types. block, error} {header: = block. Header () Number: = header. Number.uint64 () If number = = 0 {//not allowed to seal Genesis Block return nil, errunknownblock}//Jump to below clique object analysis. Does not support the 0-period chain, while refusing to seal the empty blocks, without rewards but can rotate the seal if c.config.period = = 0 && len (block.
transactions () = = 0 {return nil, errwaittransactions}//In the process of sealing block, do not hold signer signer field.
C.lock.rlock ()//Lock Gets the signer and signature method in CONFIG. Signer, Signfn: = C.signer, C.signfn c.lock.runlock () snap, err: = C.snapshot (Chain, number-1, header. Parenthash, nil)///snapshot function See below analysis//checksum processing: If we are not authorized to sign a block if Err!= nil {return nil, err} if _ , Authorized: = snap. Signers[signer];!authorized {return nil, errunauthorized}//If we are a member of the "recently signer", wait for the next block,/see below [underlying mechanism III] (HTT P://www.cnblogs.com/evsward/p/clique.html#%e4%b8%89%e8%ae%a4%e8%af%81%e7%bb%93%e7%82%b9%e7%9a%84%e5%87%ba%e5%9d%97%e6%9c%ba%e4%bc%9a%e5% 9d%87%e7%ad%89) for seen, recent: = Range snap.
recents {if recent = = signer {//signer the current signer in the "recently signer", can only continue to wait if the current block does not remove him. If limit: = UInt64 (len (SNAP). Signers)/2 + 1); Number < limit | | Seen > Number-limit {log.
Info ("Signed recently, must wait for others") <-stop return nil, nil} }//Through the above check, here is a description of the agreement has allowed us to sign this block, waiting for this work to complete delay: = time. Unix (header. Time.int64 (), 0). Sub (time. Now ()) if header. DIFFICULTY.CMP (diffnoturn) = = 0 {//This is not our rounds to sign, delay wiggle: = time. Duration (Len (SNAP). Signers)/2+1) * Wiggletime//Wiggletime = + * Time.millisecond//random delay, allowing concurrent signatures (for each signer) delay + = time. Duration (Rand. Int63n (Int64 (Wiggle)) log. Trace ("Out-of-turn signing requested", "wiggle", common. Prettyduration (Wiggle))} log. TrAce ("Waiting for slot to sign and propagate", "delay", common.) Prettyduration (delay)) Select {Case <-stop:return nil, nil case <-time. After (delay):}//Core work: Start signing Sighash, err: = SIGNFN (accounts. Account{address:signer}, Sighash (header). Bytes ())//SIGNFN function See below If Err!= nil {return nil, err} copy (header. Extra[len (header. Extra)-extraseal:]//Replace the signature result with the Extra field of the block header, which specifically supports recording additional information. Withseal (header), nil//reassemble a block by block header}
Analysis of Clique objects
Clique is the POA consensus engine, which is intended to support the Ethernet private test chain testnet (or to build its own alliance chain or private chain) after Ropsten attack,
type clique struct {
config *params. Cliqueconfig/consensus engine configuration parameters, see below Cliqueconfig source code introduction
db ethdb. db//database, used to store and get snapshot checkpoint
recents *lru. Arccache//Snapshot of the most recent block, used to speed up snapshot reorganization
signatures *LRU. Arccache//Recent block signature, used to speed up mining
proposals Map[common. Address]bool//Currently we are pushing the list of proposals, which are stored with the address and Boolean values of the key value pairs mapped
signer common. The address//signer's etheric place
signfn SIGNERFN //signature method, used to authorize hash
lock sync. Rwmutex //Lock, Secure signature field
}
Cliqueconfig Source Analysis
Cliqueconfig is the POA mining consensus engine configuration field.
type cliqueconfig struct {
Period uint64 ' json: ' Period '//The number of seconds between blocks (which can be interpreted as the elapsed time after a block out of the distance)
Epoch UInt64 ' JSON: Epoch ' //epoch[' iːpɒk ' length, resetting polling and checkpoint
}
Snapshot function Analysis
The snapshot function can obtain a certified snapshot func (c *clique) snapshot (chain consensus) by giving a fixed-point. Chainreader, number UInt64, hash common. Hash, parents []*types.
Header (*snapshot, error) {//Search for a snapshot on memory or disk to check checkpoints. var (headers []*types. header//Block Header Snap *snapshot//snapshot object, see below) for snap = = Nil {//If an in-memory snapshot is found, use the following scenario: if s , OK: = C.recents.get (hash); OK {snap = S. (*snapshot) Break}//If a snapshot of a disk checkpoint is found, use the following scenario: if Number%ch
Eckpointinterval = = 0 {//Checkpointinterval = 1024//block number, the block that holds the voting snapshot in the database. If s, err: = Loadsnapshot (C.config, C.signatures, c.db, hash); Err = = Nil {//Loadsnapshot function see below log.
Trace ("Loaded Voting snapshot form Disk", "number", Number, "hash", hash) snap = s break }//If we are in the Genesis block, then make a snapshot if number = = 0 {Genesis: = chain. Getheaderbynumber (0) If err: = C.verifyheader (Chain, Genesis, FAlse); Err!= Nil {return nil, err} signers: = Make ([]common. Address, (Len (Genesis). Extra)-extravanity-extraseal)/common. Addresslength) for I: = 0; I < Len (signers); i++ {copy (signers[i][:], Genesis. Extra[extravanity+i*common. Addresslength:])} snap = Newsnapshot (c.config, c.signatures, 0, Genesis. Hash (), signers)//Create a new snapshot of the function, see below if err: = Snap.store (c.db); Err!= Nil {return nil, err} log. Trace (' Stored Genesis voting snapshot to disk ') break}//No snapshots for the size of this area, collect block headers and move the VA back R header *types.
Header If Len (parents) > 0 {//If we have a clear parent class, force the pick out from here. Header = Parents[len (parents)-1] if header. Hash ()!= Hash | | Header. Number.uint64 ()!= number {return nil, consensus.
Errunknownancestor} parents = Parents[:len (parents)-1] else {//if there is no explicit parent class (or no more), go to database header = chain. GetHeader (hash, number) if Header = = Nil {return nil, consensus. Errunknownancestor} headers = append (headers, header) number, hash = number-1, head Er.
Parenthash}//found the previous snapshot, then put all the pending block headers on top of it. For I: = 0; I < Len (headers)/2; i++ {headers[i], Headers[len (headers) -1-i] = Headers[len (headers) -1-i], headers[i]} snap, err: = Snap.ap Ply (Headers)//Generates a new snapshot object via chunk header if Err!= nil {return nil, err} c.recents.add (s