filecoin-project / test-vectors

💎 VM and Chain test vectors for Filecoin implementations
Other
18 stars 27 forks source link

figure out preconditions and Lotus entrypoint for tipset, chain and blockseq vectors #24

Open raulk opened 4 years ago

raulk commented 4 years ago

Copied from the Chain Validation - Layer 3 requests:

Some things to be tested for a block:

  • Parents not in ticket order
  • ReceiptRoot doesn’t match StateRoot
  • ParentWeight doesn’t match
  • Signature doesn’t match
  • After a ChangeWorkerSignature, before/after that crosses lookback
  • WinningPoSt uses a faulty sector
  • Sector was ok at lookback but faulty now
  • Sector was faulty at lookback but recovered now
  • Miner doesn’t have enough power (check the boundary exactly)
  • Miner has power now but didn’t at the lookback
  • Miner had power at lookback but has less now
  • Miner has been consensus-slashed since the lookback
  • Miner doesn’t meet the consensus minimum
    • But neither do any other miners
    • But one other miner does
    • But three other miners do
    • Before/after lookback
  • Randomness lookback lands on empty tipset
  • Ticket is invalid
  • ElectionProof is invalid
  • BeaconEntries array is wrong length
  • BeaconEntries don’t form sequence

For sequences of blocks in a chain:

  • Chain weight evaluation
  • Tie-break for equally-heavy chains
  • With equal min-tickets

For ordering & finality:

  • Before finality, order does not affect chain selection. Test every permutation of block arrival across many forks with different weights.
  • Re-org to heavier chain, switch back if chain becomes relatively lighter
  • Test boundaries of long chain vs high power,
    • Switching to shorter but heavier chain
    • Switching away from a massively slashed chain (e.g. selfish mining)
    • Impact of null tipsets on weight
  • When one chain reaches finality, a heavier branch prior to finality is rejected while a heavier branch later is switched
raulk commented 4 years ago

Block validation pseudocode (Syncer#ValidateBlock)

From @nonsense's analysis:


1. cache - check if we validate already?
2. sanity checks on block.Header:
    if h.ElectionProof == nil {
        return xerrors.Errorf("block cannot have nil election proof")
    }

    if h.Ticket == nil {
        return xerrors.Errorf("block cannot have nil ticket")
    }

    if h.BlockSig == nil {
        return xerrors.Errorf("block had nil signature")
    }

    if h.BLSAggregate == nil {
        return xerrors.Errorf("block had nil bls aggregate signature")
    }
3. load parent tipset (called base tipset - `basets`)
4. lbts: get lookback tipset for round (what is that? / something to do with null rounds)
5. lbst: get `lbts` state
6. get last beacon entry (based on base tipset `basets`)
7. checking nulls / some timestamp:
    nulls := h.Height - (baseTs.Height() + 1)
    if tgtTs := baseTs.MinTimestamp() + build.BlockDelaySecs*uint64(nulls+1); h.Timestamp != tgtTs {
        return xerrors.Errorf("block has wrong timestamp: %d != %d", h.Timestamp, tgtTs)
    }
8. check that block was from the past (AllowableClockDriftSecs)
    now := uint64(build.Clock.Now().Unix())
    if h.Timestamp > now+build.AllowableClockDriftSecs {
        return xerrors.Errorf("block was from the future (now=%d, blk=%d): %w", now, h.Timestamp, ErrTemporal)
    }
    if h.Timestamp > now {
        log.Warn("Got block from the future, but within threshold", h.Timestamp, build.Clock.Now().Unix())
    }
9. check block messages
10. check that miner is valid
11. confirm base fee (fee for the base tipset)
12. confirm parent weight (again based on `baseTs`)
13. confirm stateroot for baseTs
14. check receipts root
15. minerWorkerRaw? what is that?
16. winner check:
16.1. block should claim it is a winner
16.2. check that miner has minimum power
16.3. draw randomness
16.4. validate block election PoSt VRF
16.5. check if block miner was slashed
16.6. get power
16.7. confirm number of wins that miner claims
17. check block signature
18. validate block random beacon values
19. again validate block election PoSt VRF (based on baseTs?)
20. verify winning PoSt proof
raulk commented 4 years ago

Message validation pseudocode (Syncer#checkBlockMessages, called from Syncer#ValidateBlock)

From @nonsense's analysis:

1. verify bls aggregate signature
2. get stateroot for baseTs
3. phase 1: syntactic validation - Message.ValidForBlockInclusion?
    if m.Version != 0 {
        return xerrors.New("'Version' unsupported")
    }

    if m.To == address.Undef {
        return xerrors.New("'To' address cannot be empty")
    }

    if m.From == address.Undef {
        return xerrors.New("'From' address cannot be empty")
    }

    if m.Value.Int == nil {
        return xerrors.New("'Value' cannot be nil")
    }

    if m.Value.LessThan(big.Zero()) {
        return xerrors.New("'Value' field cannot be negative")
    }

    if m.Value.GreaterThan(TotalFilecoinInt) {
        return xerrors.New("'Value' field cannot be greater than total filecoin supply")
    }

    if m.GasFeeCap.Int == nil {
        return xerrors.New("'GasFeeCap' cannot be nil")
    }

    if m.GasFeeCap.LessThan(big.Zero()) {
        return xerrors.New("'GasFeeCap' field cannot be negative")
    }

    if m.GasPremium.Int == nil {
        return xerrors.New("'GasPremium' cannot be nil")
    }

    if m.GasPremium.LessThan(big.Zero()) {
        return xerrors.New("'GasPremium' field cannot be negative")
    }

    if m.GasLimit > build.BlockGasLimit {
        return xerrors.New("'GasLimit' field cannot be greater than a block's gas limit")
    }

    // since prices might vary with time, this is technically semantic validation
    if m.GasLimit < minGas {
        return xerrors.New("'GasLimit' field cannot be less than the cost of storing a message on chain")
    }
4. phase 2: (Partial) semantic validation:
// the sender exists and is an account actor, and the nonces make sense
            if !act.IsAccountActor() {
                return xerrors.New("Sender must be an account actor")
            }
5. check each bls message
6. check each secp message