github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/consensus/istanbul/ibft/engine/engine.go (about) 1 package ibftengine 2 3 import ( 4 "bytes" 5 "math/big" 6 "time" 7 8 "github.com/kisexp/xdchain/common" 9 "github.com/kisexp/xdchain/common/hexutil" 10 "github.com/kisexp/xdchain/consensus" 11 "github.com/kisexp/xdchain/consensus/istanbul" 12 istanbulcommon "github.com/kisexp/xdchain/consensus/istanbul/common" 13 ibfttypes "github.com/kisexp/xdchain/consensus/istanbul/ibft/types" 14 "github.com/kisexp/xdchain/consensus/istanbul/validator" 15 "github.com/kisexp/xdchain/core/state" 16 "github.com/kisexp/xdchain/core/types" 17 "github.com/kisexp/xdchain/rlp" 18 "github.com/kisexp/xdchain/trie" 19 "golang.org/x/crypto/sha3" 20 ) 21 22 var ( 23 nilUncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW. 24 nonceAuthVote = hexutil.MustDecode("0xffffffffffffffff") // Magic nonce number to vote on adding a new validator 25 nonceDropVote = hexutil.MustDecode("0x0000000000000000") // Magic nonce number to vote on removing a validator. 26 ) 27 28 type SignerFn func(data []byte) ([]byte, error) 29 30 type Engine struct { 31 cfg *istanbul.Config 32 33 signer common.Address // Ethereum address of the signing key 34 sign SignerFn // Signer function to authorize hashes with 35 } 36 37 func NewEngine(cfg *istanbul.Config, signer common.Address, sign SignerFn) *Engine { 38 return &Engine{ 39 cfg: cfg, 40 signer: signer, 41 sign: sign, 42 } 43 } 44 45 func (e *Engine) Author(header *types.Header) (common.Address, error) { 46 // Retrieve the signature from the header extra-data 47 extra, err := types.ExtractIstanbulExtra(header) 48 if err != nil { 49 return common.Address{}, err 50 } 51 52 addr, err := istanbul.GetSignatureAddress(sigHash(header).Bytes(), extra.Seal) 53 if err != nil { 54 return addr, err 55 } 56 57 return addr, nil 58 } 59 60 func (e *Engine) CommitHeader(header *types.Header, seals [][]byte, round *big.Int) error { 61 // Append seals into extra-data 62 return writeCommittedSeals(header, seals) 63 } 64 65 func (e *Engine) VerifyBlockProposal(chain consensus.ChainHeaderReader, block *types.Block, validators istanbul.ValidatorSet) (time.Duration, error) { 66 // check block body 67 txnHash := types.DeriveSha(block.Transactions(), new(trie.Trie)) 68 if txnHash != block.Header().TxHash { 69 return 0, istanbulcommon.ErrMismatchTxhashes 70 } 71 72 uncleHash := types.CalcUncleHash(block.Uncles()) 73 if uncleHash != nilUncleHash { 74 return 0, istanbulcommon.ErrInvalidUncleHash 75 } 76 77 // verify the header of proposed block 78 err := e.VerifyHeader(chain, block.Header(), nil, validators) 79 if err == nil || err == istanbulcommon.ErrEmptyCommittedSeals { 80 // ignore errEmptyCommittedSeals error because we don't have the committed seals yet 81 return 0, nil 82 } else if err == consensus.ErrFutureBlock { 83 return time.Until(time.Unix(int64(block.Header().Time), 0)), consensus.ErrFutureBlock 84 } 85 86 return 0, err 87 } 88 89 func (e *Engine) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, validators istanbul.ValidatorSet) error { 90 return e.verifyHeader(chain, header, parents, validators) 91 } 92 93 // verifyHeader checks whether a header conforms to the consensus rules.The 94 // caller may optionally pass in a batch of parents (ascending order) to avoid 95 // looking those up from the database. This is useful for concurrently verifying 96 // a batch of new headers. 97 func (e *Engine) verifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, validators istanbul.ValidatorSet) error { 98 if header.Number == nil { 99 return istanbulcommon.ErrUnknownBlock 100 } 101 102 // Don't waste time checking blocks from the future (adjusting for allowed threshold) 103 adjustedTimeNow := time.Now().Add(time.Duration(e.cfg.AllowedFutureBlockTime) * time.Second).Unix() 104 if header.Time > uint64(adjustedTimeNow) { 105 return consensus.ErrFutureBlock 106 } 107 108 if _, err := types.ExtractIstanbulExtra(header); err != nil { 109 return istanbulcommon.ErrInvalidExtraDataFormat 110 } 111 112 if header.Nonce != (istanbulcommon.EmptyBlockNonce) && !bytes.Equal(header.Nonce[:], nonceAuthVote) && !bytes.Equal(header.Nonce[:], nonceDropVote) { 113 return istanbulcommon.ErrInvalidNonce 114 } 115 116 // Ensure that the mix digest is zero as we don't have fork protection currently 117 if header.MixDigest != types.IstanbulDigest { 118 return istanbulcommon.ErrInvalidMixDigest 119 } 120 121 // Ensure that the block doesn't contain any uncles which are meaningless in Istanbul 122 if header.UncleHash != nilUncleHash { 123 return istanbulcommon.ErrInvalidUncleHash 124 } 125 126 // Ensure that the block's difficulty is meaningful (may not be correct at this point) 127 if header.Difficulty == nil || header.Difficulty.Cmp(istanbulcommon.DefaultDifficulty) != 0 { 128 return istanbulcommon.ErrInvalidDifficulty 129 } 130 131 return e.verifyCascadingFields(chain, header, validators, parents) 132 } 133 134 // verifyCascadingFields verifies all the header fields that are not standalone, 135 // rather depend on a batch of previous headers. The caller may optionally pass 136 // in a batch of parents (ascending order) to avoid looking those up from the 137 // database. This is useful for concurrently verifying a batch of new headers. 138 func (e *Engine) verifyCascadingFields(chain consensus.ChainHeaderReader, header *types.Header, validators istanbul.ValidatorSet, parents []*types.Header) error { 139 // The genesis block is the always valid dead-end 140 number := header.Number.Uint64() 141 if number == 0 { 142 return nil 143 } 144 145 // Check parent 146 var parent *types.Header 147 if len(parents) > 0 { 148 parent = parents[len(parents)-1] 149 } else { 150 parent = chain.GetHeader(header.ParentHash, number-1) 151 } 152 153 // Ensure that the block's parent has right number and hash 154 if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { 155 return consensus.ErrUnknownAncestor 156 } 157 158 // Ensure that the block's timestamp isn't too close to it's parent 159 if parent.Time+e.cfg.BlockPeriod > header.Time { 160 return istanbulcommon.ErrInvalidTimestamp 161 } 162 163 // Verify signer 164 if err := e.verifySigner(chain, header, parents, validators); err != nil { 165 return err 166 } 167 168 return e.verifyCommittedSeals(chain, header, parents, validators) 169 } 170 171 func (e *Engine) verifySigner(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, validators istanbul.ValidatorSet) error { 172 // Verifying the genesis block is not supported 173 number := header.Number.Uint64() 174 if number == 0 { 175 return istanbulcommon.ErrUnknownBlock 176 } 177 178 // Resolve the authorization key and check against signers 179 signer, err := e.Author(header) 180 if err != nil { 181 return err 182 } 183 184 // Signer should be in the validator set of previous block's extraData. 185 if _, v := validators.GetByAddress(signer); v == nil { 186 return istanbulcommon.ErrUnauthorized 187 } 188 189 return nil 190 } 191 192 // verifyCommittedSeals checks whether every committed seal is signed by one of the parent's validators 193 func (e *Engine) verifyCommittedSeals(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header, validators istanbul.ValidatorSet) error { 194 number := header.Number.Uint64() 195 196 if number == 0 { 197 // We don't need to verify committed seals in the genesis block 198 return nil 199 } 200 201 extra, err := types.ExtractIstanbulExtra(header) 202 if err != nil { 203 return err 204 } 205 committedSeal := extra.CommittedSeal 206 207 // The length of Committed seals should be larger than 0 208 if len(committedSeal) == 0 { 209 return istanbulcommon.ErrEmptyCommittedSeals 210 } 211 212 validatorsCpy := validators.Copy() 213 214 // Check whether the committed seals are generated by validators 215 validSeal := 0 216 committers, err := e.Signers(header) 217 if err != nil { 218 return err 219 } 220 221 for _, addr := range committers { 222 if validatorsCpy.RemoveValidator(addr) { 223 validSeal++ 224 continue 225 } 226 return istanbulcommon.ErrInvalidCommittedSeals 227 } 228 229 // The length of validSeal should be larger than number of faulty node + 1 230 if validSeal <= validators.F() { 231 return istanbulcommon.ErrInvalidCommittedSeals 232 } 233 234 return nil 235 } 236 237 // VerifyUncles verifies that the given block's uncles conform to the consensus 238 // rules of a given engine. 239 func (e *Engine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { 240 if len(block.Uncles()) > 0 { 241 return istanbulcommon.ErrInvalidUncleHash 242 } 243 return nil 244 } 245 246 // VerifySeal checks whether the crypto seal on a header is valid according to 247 // the consensus rules of the given engine. 248 func (e *Engine) VerifySeal(chain consensus.ChainHeaderReader, header *types.Header, validators istanbul.ValidatorSet) error { 249 250 // get parent header and ensure the signer is in parent's validator set 251 number := header.Number.Uint64() 252 if number == 0 { 253 return istanbulcommon.ErrUnknownBlock 254 } 255 256 // ensure that the difficulty equals to istanbulcommon.DefaultDifficulty 257 if header.Difficulty.Cmp(istanbulcommon.DefaultDifficulty) != 0 { 258 return istanbulcommon.ErrInvalidDifficulty 259 } 260 261 return e.verifySigner(chain, header, nil, validators) 262 } 263 264 func (e *Engine) Prepare(chain consensus.ChainHeaderReader, header *types.Header, validators istanbul.ValidatorSet) error { 265 header.Coinbase = common.Address{} 266 header.Nonce = istanbulcommon.EmptyBlockNonce 267 header.MixDigest = types.IstanbulDigest 268 269 // copy the parent extra data as the header extra data 270 number := header.Number.Uint64() 271 parent := chain.GetHeader(header.ParentHash, number-1) 272 if parent == nil { 273 return consensus.ErrUnknownAncestor 274 } 275 276 // use the same difficulty for all blocks 277 header.Difficulty = istanbulcommon.DefaultDifficulty 278 279 // add validators in snapshot to extraData's validators section 280 extra, err := prepareExtra(header, validator.SortedAddresses(validators.List())) 281 if err != nil { 282 return err 283 } 284 header.Extra = extra 285 286 // set header's timestamp 287 header.Time = parent.Time + e.cfg.BlockPeriod 288 if header.Time < uint64(time.Now().Unix()) { 289 header.Time = uint64(time.Now().Unix()) 290 } 291 292 return nil 293 } 294 295 // Finalize runs any post-transaction state modifications (e.g. block rewards) 296 // and assembles the final block. 297 // 298 // Note, the block header and state database might be updated to reflect any 299 // consensus rules that happen at finalization (e.g. block rewards). 300 func (e *Engine) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { 301 // No block rewards in Istanbul, so the state remains as is and uncles are dropped 302 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 303 header.UncleHash = nilUncleHash 304 } 305 306 // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, 307 // nor block rewards given, and returns the final block. 308 func (e *Engine) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { 309 /// No block rewards in Istanbul, so the state remains as is and uncles are dropped 310 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 311 header.UncleHash = nilUncleHash 312 313 // Assemble and return the final block for sealing 314 return types.NewBlock(header, txs, nil, receipts, new(trie.Trie)), nil 315 } 316 317 // Seal generates a new block for the given input block with the local miner's 318 // seal place on top. 319 func (e *Engine) Seal(chain consensus.ChainHeaderReader, block *types.Block, validators istanbul.ValidatorSet) (*types.Block, error) { 320 // update the block header timestamp and signature and propose the block to core engine 321 header := block.Header() 322 number := header.Number.Uint64() 323 324 if _, v := validators.GetByAddress(e.signer); v == nil { 325 return block, istanbulcommon.ErrUnauthorized 326 } 327 328 parent := chain.GetHeader(header.ParentHash, number-1) 329 if parent == nil { 330 return block, consensus.ErrUnknownAncestor 331 } 332 333 return e.updateBlock(parent, block) 334 } 335 336 // update timestamp and signature of the block based on its number of transactions 337 func (e *Engine) updateBlock(parent *types.Header, block *types.Block) (*types.Block, error) { 338 // sign the hash 339 header := block.Header() 340 seal, err := e.sign(sigHash(header).Bytes()) 341 if err != nil { 342 return nil, err 343 } 344 345 err = writeSeal(header, seal) 346 if err != nil { 347 return nil, err 348 } 349 350 return block.WithSeal(header), nil 351 } 352 353 // writeSeal writes the extra-data field of the given header with the given seals. 354 // suggest to rename to writeSeal. 355 func writeSeal(h *types.Header, seal []byte) error { 356 if len(seal)%types.IstanbulExtraSeal != 0 { 357 return istanbulcommon.ErrInvalidSignature 358 } 359 360 istanbulExtra, err := types.ExtractIstanbulExtra(h) 361 if err != nil { 362 return err 363 } 364 365 istanbulExtra.Seal = seal 366 payload, err := rlp.EncodeToBytes(&istanbulExtra) 367 if err != nil { 368 return err 369 } 370 371 h.Extra = append(h.Extra[:types.IstanbulExtraVanity], payload...) 372 return nil 373 } 374 375 func (e *Engine) SealHash(header *types.Header) common.Hash { 376 return sigHash(header) 377 } 378 379 func (e *Engine) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { 380 return new(big.Int) 381 } 382 383 func (e *Engine) Validators(header *types.Header) ([]common.Address, error) { 384 extra, err := types.ExtractIstanbulExtra(header) 385 if err != nil { 386 return nil, err 387 } 388 389 return extra.Validators, nil 390 } 391 392 func (e *Engine) Signers(header *types.Header) ([]common.Address, error) { 393 extra, err := types.ExtractIstanbulExtra(header) 394 if err != nil { 395 return []common.Address{}, err 396 } 397 committedSeal := extra.CommittedSeal 398 proposalSeal := PrepareCommittedSeal(header.Hash()) 399 400 var addrs []common.Address 401 // 1. Get committed seals from current header 402 for _, seal := range committedSeal { 403 // 2. Get the original address by seal and parent block hash 404 addr, err := istanbulcommon.GetSignatureAddress(proposalSeal, seal) 405 if err != nil { 406 return nil, istanbulcommon.ErrInvalidSignature 407 } 408 addrs = append(addrs, addr) 409 } 410 411 return addrs, nil 412 } 413 414 func (e *Engine) Address() common.Address { 415 return e.signer 416 } 417 418 func (e *Engine) WriteVote(header *types.Header, candidate common.Address, authorize bool) error { 419 header.Coinbase = candidate 420 if authorize { 421 copy(header.Nonce[:], nonceAuthVote) 422 } else { 423 copy(header.Nonce[:], nonceDropVote) 424 } 425 426 return nil 427 } 428 429 func (e *Engine) ReadVote(header *types.Header) (candidate common.Address, authorize bool, err error) { 430 switch { 431 case bytes.Equal(header.Nonce[:], nonceAuthVote): 432 authorize = true 433 case bytes.Equal(header.Nonce[:], nonceDropVote): 434 authorize = false 435 default: 436 return common.Address{}, false, istanbulcommon.ErrInvalidVote 437 } 438 439 return header.Coinbase, authorize, nil 440 } 441 442 // FIXME: Need to update this for Istanbul 443 // sigHash returns the hash which is used as input for the Istanbul 444 // signing. It is the hash of the entire header apart from the 65 byte signature 445 // contained at the end of the extra data. 446 // 447 // Note, the method requires the extra data to be at least 65 bytes, otherwise it 448 // panics. This is done to avoid accidentally using both forms (signature present 449 // or not), which could be abused to produce different hashes for the same header. 450 func sigHash(header *types.Header) (hash common.Hash) { 451 hasher := sha3.NewLegacyKeccak256() 452 rlp.Encode(hasher, types.IstanbulFilteredHeader(header, false)) 453 hasher.Sum(hash[:0]) 454 return hash 455 } 456 457 // prepareExtra returns a extra-data of the given header and validators 458 func prepareExtra(header *types.Header, vals []common.Address) ([]byte, error) { 459 var buf bytes.Buffer 460 461 // compensate the lack bytes if header.Extra is not enough IstanbulExtraVanity bytes. 462 if len(header.Extra) < types.IstanbulExtraVanity { 463 header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity-len(header.Extra))...) 464 } 465 buf.Write(header.Extra[:types.IstanbulExtraVanity]) 466 467 ist := &types.IstanbulExtra{ 468 Validators: vals, 469 Seal: []byte{}, 470 CommittedSeal: [][]byte{}, 471 } 472 473 payload, err := rlp.EncodeToBytes(&ist) 474 if err != nil { 475 return nil, err 476 } 477 478 return append(buf.Bytes(), payload...), nil 479 } 480 481 func writeCommittedSeals(h *types.Header, committedSeals [][]byte) error { 482 if len(committedSeals) == 0 { 483 return istanbulcommon.ErrInvalidCommittedSeals 484 } 485 486 for _, seal := range committedSeals { 487 if len(seal) != types.IstanbulExtraSeal { 488 return istanbulcommon.ErrInvalidCommittedSeals 489 } 490 } 491 492 istanbulExtra, err := types.ExtractIstanbulExtra(h) 493 if err != nil { 494 return err 495 } 496 497 istanbulExtra.CommittedSeal = make([][]byte, len(committedSeals)) 498 copy(istanbulExtra.CommittedSeal, committedSeals) 499 500 payload, err := rlp.EncodeToBytes(&istanbulExtra) 501 if err != nil { 502 return err 503 } 504 505 h.Extra = append(h.Extra[:types.IstanbulExtraVanity], payload...) 506 return nil 507 } 508 509 // PrepareCommittedSeal returns a committed seal for the given hash 510 func PrepareCommittedSeal(hash common.Hash) []byte { 511 var buf bytes.Buffer 512 buf.Write(hash.Bytes()) 513 buf.Write([]byte{byte(ibfttypes.MsgCommit)}) 514 return buf.Bytes() 515 }