more audit todos and fixes (#2489)

pull/2490/head
Rongjian Lan 5 years ago committed by GitHub
parent 4c40ad3eb1
commit 71361da6bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      consensus/consensus.go
  2. 1
      consensus/leader.go
  3. 1
      core/rawdb/accessors_offchain.go
  4. 5
      internal/chain/engine.go
  5. 6
      node/worker/worker.go
  6. 29
      shard/committee/assignment.go
  7. 6
      staking/effective/calculate.go
  8. 8
      staking/slash/double-sign.go

@ -79,8 +79,9 @@ type Consensus struct {
MinPeers int MinPeers int
pubKeyLock sync.Mutex pubKeyLock sync.Mutex
// private/public keys of current node // private/public keys of current node
priKey *multibls.PrivateKey priKey *multibls.PrivateKey
PubKey *multibls.PublicKey PubKey *multibls.PublicKey
// TODO(audit): SelfAddresses doesn't have the ECDSA address for external validators. Don't use it that way.
SelfAddresses map[string]common.Address SelfAddresses map[string]common.Address
// the publickey of leader // the publickey of leader
LeaderPubKey *bls.PublicKey LeaderPubKey *bls.PublicKey

@ -209,6 +209,7 @@ func (consensus *Consensus) onCommit(msg *msg_pb.Message) {
consensus.mutex.Lock() consensus.mutex.Lock()
defer consensus.mutex.Unlock() defer consensus.mutex.Unlock()
// TODO(audit): refactor into a new func
if key := (bls.PublicKey{}); consensus.couldThisBeADoubleSigner(recvMsg) { if key := (bls.PublicKey{}); consensus.couldThisBeADoubleSigner(recvMsg) {
if alreadyCastBallot := consensus.Decider.ReadBallot( if alreadyCastBallot := consensus.Decider.ReadBallot(
quorum.Commit, recvMsg.SenderPubkey, quorum.Commit, recvMsg.SenderPubkey,

@ -106,6 +106,7 @@ func DeletePendingCrossLinks(db DatabaseDeleter) error {
} }
// ReadPendingSlashingCandidates retrieves last pending slashing candidates // ReadPendingSlashingCandidates retrieves last pending slashing candidates
// TODO(audit): the pending slashes written in DB is never used.
func ReadPendingSlashingCandidates(db DatabaseReader) ([]byte, error) { func ReadPendingSlashingCandidates(db DatabaseReader) ([]byte, error) {
return db.Get(pendingSlashingKey) return db.Get(pendingSlashingKey)
} }

@ -290,6 +290,8 @@ func (e *engineImpl) Finalize(
if err := applySlashes(chain, header, state, doubleSigners); err != nil { if err := applySlashes(chain, header, state, doubleSigners); err != nil {
return nil, nil, err return nil, nil, err
} }
} else if len(doubleSigners) > 0 {
return nil, nil, errors.New("slashes proposed in non-beacon chain or non-staking epoch")
} }
// Finalize the state root // Finalize the state root
@ -370,6 +372,7 @@ func applySlashes(
state *state.DB, state *state.DB,
doubleSigners slash.Records, doubleSigners slash.Records,
) error { ) error {
// TODO(audit): should read from the epoch when the slash happened
superCommittee, err := chain.ReadShardState(chain.CurrentHeader().Epoch()) superCommittee, err := chain.ReadShardState(chain.CurrentHeader().Epoch())
if err != nil { if err != nil {
@ -379,6 +382,8 @@ func applySlashes(
staked := superCommittee.StakedValidators() staked := superCommittee.StakedValidators()
// Apply the slashes, invariant: assume been verified as legit slash by this point // Apply the slashes, invariant: assume been verified as legit slash by this point
var slashApplied *slash.Application var slashApplied *slash.Application
// TODO(audit): need to group doubleSigners by the target (block) and slash them separately
// the rate of slash should be based on num_keys_signed_on_same_block/total_bls_key
rate := slash.Rate(len(doubleSigners), staked.CountStakedBLSKey) rate := slash.Rate(len(doubleSigners), staked.CountStakedBLSKey)
utils.Logger().Info(). utils.Logger().Info().
Str("rate", rate.String()). Str("rate", rate.String()).

@ -359,7 +359,11 @@ func (w *Worker) verifySlashes(
}, },
) )
workingState := w.GetCurrentState() // Always base the state on current tip of the chain
workingState, err := w.chain.State()
if err != nil {
return successes, failures
}
for i := range d { for i := range d {
if err := slash.Verify( if err := slash.Verify(

@ -171,6 +171,7 @@ func eposStakedCommittee(
if validator.EPOSStatus != effective.Active { if validator.EPOSStatus != effective.Active {
continue continue
} }
// TODO(audit): remove the sanity check here; do the sanity check with maxBLSKey before validator change
if err := validator.SanityCheck(maxBLSKey); err != nil { if err := validator.SanityCheck(maxBLSKey); err != nil {
utils.Logger().Info(). utils.Logger().Info().
Int("staked-candidates", len(candidates)). Int("staked-candidates", len(candidates)).
@ -178,10 +179,7 @@ func eposStakedCommittee(
Msg("validator sanity check failed") Msg("validator sanity check failed")
continue continue
} }
validatorStake := big.NewInt(0) totalStake := validator.TotalDelegation()
for _, delegation := range validator.Delegations {
validatorStake.Add(validatorStake, delegation.Amount)
}
found := false found := false
dupKey := shard.BlsPublicKey{} dupKey := shard.BlsPublicKey{}
@ -202,28 +200,23 @@ func eposStakedCommittee(
} }
essentials[validator.Address] = effective.SlotOrder{ essentials[validator.Address] = effective.SlotOrder{
validatorStake, totalStake,
validator.SlotPubKeys, validator.SlotPubKeys,
} }
} }
staked := effective.Apply(essentials, stakedSlotsCount) electedSlots := effective.Apply(essentials, stakedSlotsCount)
shardBig := big.NewInt(int64(shardCount)) shardBig := big.NewInt(int64(shardCount))
if l := len(staked); l < stakedSlotsCount { totalEffectiveStake := numeric.ZeroDec()
// WARN unlikely to happen in production but will happen as we are developing
stakedSlotsCount = l
}
totalStake := numeric.ZeroDec()
for i := 0; i < stakedSlotsCount; i++ { for i := 0; i < len(electedSlots); i++ {
shardID := int(new(big.Int).Mod(staked[i].BlsPublicKey.Big(), shardBig).Int64()) slot := electedSlots[i]
slot := staked[i] shardID := int(new(big.Int).Mod(slot.BlsPublicKey.Big(), shardBig).Int64())
totalStake = totalStake.Add(slot.Dec) totalEffectiveStake = totalEffectiveStake.Add(slot.Dec)
shardState.Shards[shardID].Slots = append(shardState.Shards[shardID].Slots, shard.Slot{ shardState.Shards[shardID].Slots = append(shardState.Shards[shardID].Slots, shard.Slot{
slot.Address, slot.Address,
staked[i].BlsPublicKey, slot.BlsPublicKey,
&slot.Dec, &slot.Dec,
}) })
} }
@ -231,7 +224,7 @@ func eposStakedCommittee(
if c := len(candidates); c != 0 { if c := len(candidates); c != 0 {
utils.Logger().Info(). utils.Logger().Info().
Int("staked-candidates", c). Int("staked-candidates", c).
Str("total-staked-by-validators", totalStake.String()). Str("sum-all-effective-stake-by-validators", totalEffectiveStake.String()).
Msg("epos based super-committe") Msg("epos based super-committe")
} }

@ -68,7 +68,6 @@ func (s Slots) JSON() string {
// Median .. // Median ..
func Median(stakes []SlotPurchase) numeric.Dec { func Median(stakes []SlotPurchase) numeric.Dec {
if len(stakes) == 0 { if len(stakes) == 0 {
utils.Logger().Error().Int("non-zero", len(stakes)). utils.Logger().Error().Int("non-zero", len(stakes)).
Msg("Input to median has len 0, check caller") Msg("Input to median has len 0, check caller")
@ -76,7 +75,7 @@ func Median(stakes []SlotPurchase) numeric.Dec {
sort.SliceStable( sort.SliceStable(
stakes, stakes,
func(i, j int) bool { return stakes[i].Dec.LT(stakes[j].Dec) }, func(i, j int) bool { return stakes[i].Dec.GT(stakes[j].Dec) },
) )
const isEven = 0 const isEven = 0
switch l := len(stakes); l % 2 { switch l := len(stakes); l % 2 {
@ -132,9 +131,6 @@ func Compute(
}) })
} }
} }
if len(eposedSlots) < len(shortHand) {
// WARN Should never happen
}
sort.SliceStable( sort.SliceStable(
eposedSlots, eposedSlots,

@ -186,9 +186,8 @@ func Verify(
) )
} }
currentEpoch := chain.CurrentBlock().Epoch() currentEpoch := chain.CurrentBlock().Epoch()
// on beaconchain committee, the slash can't come from the future // the slash can't come from the future (shard chain's epoch can't be larger than beacon chain's)
if candidate.Evidence.ShardID == shard.BeaconChainShardID && if candidate.Evidence.Epoch.Cmp(currentEpoch) == 1 {
candidate.Evidence.Epoch.Cmp(currentEpoch) == 1 {
return errors.Wrapf( return errors.Wrapf(
errSlashFromFutureEpoch, "current-epoch %v", currentEpoch, errSlashFromFutureEpoch, "current-epoch %v", currentEpoch,
) )
@ -232,6 +231,7 @@ func Verify(
} }
blockNumBytes := make([]byte, 8) blockNumBytes := make([]byte, 8)
// TODO(audit): add view ID into signature payload
binary.LittleEndian.PutUint64(blockNumBytes, ballot.Height) binary.LittleEndian.PutUint64(blockNumBytes, ballot.Height)
commitPayload := append(blockNumBytes, ballot.BlockHeaderHash[:]...) commitPayload := append(blockNumBytes, ballot.BlockHeaderHash[:]...)
if !signature.VerifyHash(publicKey, commitPayload) { if !signature.VerifyHash(publicKey, commitPayload) {
@ -362,7 +362,7 @@ func delegatorSlashApply(
} }
if nowAmt.Cmp(common.Big0) == 0 { if nowAmt.Cmp(common.Big0) == 0 {
// TODO need to remove the undelegate // TODO(audit): need to remove the undelegate
utils.Logger().Info(). utils.Logger().Info().
RawJSON("delegation-snapshot", []byte(delegationSnapshot.String())). RawJSON("delegation-snapshot", []byte(delegationSnapshot.String())).
RawJSON("delegation-current", []byte(delegationNow.String())). RawJSON("delegation-current", []byte(delegationNow.String())).

Loading…
Cancel
Save