ValidateBlock validates a block and the transactions within. It does not run the consensus program; for that, see ValidateBlockSig.
(b, prev *bc.Block, initialBlockID bc.Hash, validateTx func(*bc.Tx) error)
| 453 | // ValidateBlock validates a block and the transactions within. |
| 454 | // It does not run the consensus program; for that, see ValidateBlockSig. |
| 455 | func ValidateBlock(b, prev *bc.Block, initialBlockID bc.Hash, validateTx func(*bc.Tx) error) error { |
| 456 | if b.Height > 1 { |
| 457 | if prev == nil { |
| 458 | return errors.WithDetailf(errNoPrevBlock, "height %d", b.Height) |
| 459 | } |
| 460 | err := validateBlockAgainstPrev(b, prev) |
| 461 | if err != nil { |
| 462 | return err |
| 463 | } |
| 464 | } |
| 465 | |
| 466 | err := checkValidBlockHeader(b.BlockHeader) |
| 467 | if err != nil { |
| 468 | return errors.Wrap(err, "checking block header") |
| 469 | } |
| 470 | |
| 471 | for i, tx := range b.Transactions { |
| 472 | if b.Version == 1 && tx.Version != 1 { |
| 473 | return errors.WithDetailf(errTxVersion, "block version %d, transaction version %d", b.Version, tx.Version) |
| 474 | } |
| 475 | if tx.MaxTimeMs > 0 && b.TimestampMs > tx.MaxTimeMs { |
| 476 | return errors.WithDetailf(errUntimelyTransaction, "block timestamp %d, transaction time range %d-%d", b.TimestampMs, tx.MinTimeMs, tx.MaxTimeMs) |
| 477 | } |
| 478 | if tx.MinTimeMs > 0 && b.TimestampMs > 0 && b.TimestampMs < tx.MinTimeMs { |
| 479 | return errors.WithDetailf(errUntimelyTransaction, "block timestamp %d, transaction time range %d-%d", b.TimestampMs, tx.MinTimeMs, tx.MaxTimeMs) |
| 480 | } |
| 481 | |
| 482 | err = validateTx(tx) |
| 483 | if err != nil { |
| 484 | return errors.Wrapf(err, "validity of transaction %d of %d", i, len(b.Transactions)) |
| 485 | } |
| 486 | } |
| 487 | |
| 488 | txRoot, err := bc.MerkleRoot(b.Transactions) |
| 489 | if err != nil { |
| 490 | return errors.Wrap(err, "computing transaction merkle root") |
| 491 | } |
| 492 | |
| 493 | if txRoot != *b.TransactionsRoot { |
| 494 | return errors.WithDetailf(errMismatchedMerkleRoot, "computed %x, current block wants %x", txRoot.Bytes(), b.TransactionsRoot.Bytes()) |
| 495 | } |
| 496 | |
| 497 | return nil |
| 498 | } |
| 499 | |
| 500 | func validateBlockAgainstPrev(b, prev *bc.Block) error { |
| 501 | if b.Version < prev.Version { |