}
// SaveCheckpoints bulk save multiple checkpoint
-func (s *Store) SaveCheckpoints(checkpoints ...*state.Checkpoint) error {
+func (s *Store) SaveCheckpoints(checkpoints []*state.Checkpoint) error {
batch := s.db.NewBatch()
if err := s.saveCheckpoints(batch, checkpoints); err != nil {
return nil, nil, err
}
- if err := c.applySupLinks(target, block.SupLinks, validators); err != nil {
+ affectedCheckpoints, err := c.applySupLinks(target, block.SupLinks, validators)
+ if err != nil {
return nil, nil, err
}
- return verification, target, nil
+ return verification, target, c.saveCheckpoints(affectedCheckpoints, target)
}
func (c *Casper) applyBlockToCheckpoint(block *types.Block) (*state.Checkpoint, error) {
}
// applySupLinks copy the block's supLink to the checkpoint
-func (c *Casper) applySupLinks(target *state.Checkpoint, supLinks []*types.SupLink, validators map[string]*state.Validator) error {
+func (c *Casper) applySupLinks(target *state.Checkpoint, supLinks []*types.SupLink, validators map[string]*state.Validator) (map[bc.Hash]*state.Checkpoint, error) {
if target.Height%state.BlocksOfEpoch != 0 {
- return nil
+ return nil, nil
}
affectedCheckpoints := make(map[bc.Hash]*state.Checkpoint)
checkpoints, err := c.addVerificationToCheckpoint(target, validators, validVerifications...)
if err != nil {
- return err
+ return nil, err
}
for _, c := range checkpoints {
}
}
- delete(affectedCheckpoints, target.Hash)
- var checkpoints []*state.Checkpoint
- for _, c := range affectedCheckpoints {
- checkpoints = append(checkpoints, c)
- }
- return c.store.SaveCheckpoints(checkpoints...)
+ return affectedCheckpoints, nil
}
func (c *Casper) applyMyVerification(target *state.Checkpoint, block *types.Block, validators map[string]*state.Validator) (*Verification, error) {
}
validatorOrder := validators[pubKey].Order
- source := c.lastJustifiedCheckpointOfBranch(target)
- if target.ContainsVerification(source.Hash, validatorOrder) {
+ if target.ContainsVerification(validatorOrder, nil) {
return nil, nil
}
- if source != nil {
+ if source := c.lastJustifiedCheckpointOfBranch(target); source != nil {
v := &Verification{
SourceHash: source.Hash,
TargetHash: target.Hash,
return nil, nil
}
+func (c *Casper) saveCheckpoints(affectedCheckpoints map[bc.Hash]*state.Checkpoint, target *state.Checkpoint) error {
+ // the target checkpoint must eventually be saved in the chain state
+ delete(affectedCheckpoints, target.Hash)
+
+ var checkpoints []*state.Checkpoint
+ for _, c := range affectedCheckpoints {
+ checkpoints = append(checkpoints, c)
+ }
+ return c.store.SaveCheckpoints(checkpoints)
+}
+
+
type guarantyArgs struct {
Amount uint64
PubKey []byte
return errPubKeyIsNotValidator
}
- if target.ContainsVerification(v.SourceHash, validators[v.PubKey].Order) {
+ if target.ContainsVerification(validators[v.PubKey].Order, &v.SourceHash) {
return nil
}
return err
}
- if err := c.store.SaveCheckpoints(checkpoints...); err != nil {
+ if err := c.store.SaveCheckpoints(checkpoints); err != nil {
return err
}
_, newBestHash := c.bestChain()
if oldBestHash != newBestHash {
- c.rollbackNotifyCh <- nil
+ c.rollbackNotifyCh <- newBestHash
}
return affectedCheckpoints, nil
case msg := <-c.processBlockCh:
isOrphan, err := c.processBlock(msg.block)
msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err}
- case <-c.rollbackNotifyCh:
- if err := c.rollback(); err != nil {
+ case newBestHash := <-c.rollbackNotifyCh:
+ if err := c.rollback(newBestHash); err != nil {
log.WithFields(log.Fields{"module": logModule, "err": err}).Warning("fail on rollback block")
}
}
return false, nil
}
-func (c *Chain) rollback() error {
- latestBestBlockHash := c.latestBestBlockHash()
- if c.bestNode.Hash == *latestBestBlockHash {
+func (c *Chain) rollback(newBestHash bc.Hash) error {
+ if c.bestNode.Hash == newBestHash {
return nil
}
- node := c.index.GetNode(latestBestBlockHash)
+ node := c.index.GetNode(&newBestHash)
log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain")
return c.reorganizeChain(node)
}
type Casper struct {
mu sync.RWMutex
tree *treeNode
- rollbackNotifyCh chan interface{}
+ rollbackNotifyCh chan bc.Hash
newEpochCh chan bc.Hash
store Store
// pubKey -> conflicting verifications
// argument checkpoints load the checkpoints from leveldb
// the first element of checkpoints must genesis checkpoint or the last finalized checkpoint in order to reduce memory space
// the others must be successors of first one
-func NewCasper(store Store, checkpoints []*state.Checkpoint, rollbackNotifyCh chan interface{}) *Casper {
+func NewCasper(store Store, checkpoints []*state.Checkpoint, rollbackNotifyCh chan bc.Hash) *Casper {
if checkpoints[0].Height != 0 && checkpoints[0].Status != state.Finalized {
log.Panic("first element of checkpoints must genesis or in finalized status")
}
store Store
casper *Casper
processBlockCh chan *processBlockMsg
- rollbackNotifyCh chan interface{}
+ rollbackNotifyCh chan bc.Hash
eventDispatcher *event.Dispatcher
cond sync.Cond
eventDispatcher: eventDispatcher,
txPool: txPool,
store: store,
- rollbackNotifyCh: make(chan interface{}),
+ rollbackNotifyCh: make(chan bc.Hash),
processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
}
c.cond.L = new(sync.Mutex)
return c.store.SaveChainStatus(node, utxoView, contractView, []*state.Checkpoint{checkpoint}, 0, &checkpoint.Hash)
}
-func newCasper(store Store, storeStatus *BlockStoreState, rollbackNotifyCh chan interface{}) (*Casper, error) {
+func newCasper(store Store, storeStatus *BlockStoreState, rollbackNotifyCh chan bc.Hash) (*Casper, error) {
checkpoints, err := store.CheckpointsFromNode(storeStatus.FinalizedHeight, storeStatus.FinalizedHash)
if err != nil {
return nil, err
return &c.bestNode.Hash
}
-func (c *Chain) latestBestBlockHash() *bc.Hash {
- _, hash := c.casper.BestChain()
- return &hash
-}
-
// GetValidator return validator by specified blockHash and timestamp
func (c *Chain) GetValidator(prevHash *bc.Hash, timeStamp uint64) (*state.Validator, error) {
prevCheckpoint, err := c.casper.prevCheckpointByPrevHash(prevHash)
}
// ContainsVerification return whether the specified validator has add verification to current checkpoint
-func (c *Checkpoint) ContainsVerification(sourceHash bc.Hash, validatorOrder int) bool {
+// sourceHash not as filter if is nil,
+func (c *Checkpoint) ContainsVerification(validatorOrder int, sourceHash *bc.Hash) bool {
for _, supLink := range c.SupLinks {
- if supLink.SourceHash == sourceHash && supLink.Signatures[validatorOrder] != "" {
+ if (sourceHash == nil || supLink.SourceHash == *sourceHash) && supLink.Signatures[validatorOrder] != "" {
return true
}
}
GetCheckpoint(*bc.Hash) (*state.Checkpoint, error)
CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error)
GetCheckpointsByHeight(uint64) ([]*state.Checkpoint, error)
- SaveCheckpoints(...*state.Checkpoint) error
+ SaveCheckpoints([]*state.Checkpoint) error
LoadBlockIndex(uint64) (*state.BlockIndex, error)
SaveBlock(*types.Block) error
func (s *mockStore) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) { return nil, nil }
func (s *mockStore) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error) { return nil, nil }
func (s *mockStore) GetCheckpointsByHeight(u uint64) ([]*state.Checkpoint, error) { return nil, nil }
-func (s *mockStore) SaveCheckpoints(...*state.Checkpoint) error { return nil }
+func (s *mockStore) SaveCheckpoints([]*state.Checkpoint) error { return nil }
func (s *mockStore) CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error) { return nil, nil }
func (s *mockStore) BlockExist(hash *bc.Hash) bool { return false }
func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
func (s *mockStore1) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) { return nil, nil }
func (s *mockStore1) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error) { return nil, nil }
func (s *mockStore1) GetCheckpointsByHeight(u uint64) ([]*state.Checkpoint, error) { return nil, nil }
-func (s *mockStore1) SaveCheckpoints(...*state.Checkpoint) error { return nil }
+func (s *mockStore1) SaveCheckpoints([]*state.Checkpoint) error { return nil }
func (s *mockStore1) CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error) { return nil, nil }
func (s *mockStore1) BlockExist(hash *bc.Hash) bool { return false }
func (s *mockStore1) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
PubKey string
}
-// EncodeMessage encode the verification for the validators to sign or verify
-func (v *Verification) EncodeMessage() ([]byte, error) {
- buff := new(bytes.Buffer)
- if _, err := v.SourceHash.WriteTo(buff); err != nil {
- return nil, err
- }
-
- if _, err := v.TargetHash.WriteTo(buff); err != nil {
- return nil, err
- }
-
- uint64Buff := make([]byte, 8)
-
- binary.LittleEndian.PutUint64(uint64Buff, v.SourceHeight)
- if _, err := buff.Write(uint64Buff); err != nil {
- return nil, err
- }
-
- binary.LittleEndian.PutUint64(uint64Buff, v.TargetHeight)
- if _, err := buff.Write(uint64Buff); err != nil {
- return nil, err
- }
-
- return sha3Hash(buff.Bytes())
-}
-
// Sign used to sign the verification by specified xPrv
func (v *Verification) Sign(xPrv chainkd.XPrv) error {
- message, err := v.EncodeMessage()
+ message, err := v.encodeMessage()
if err != nil {
return err
}
return err
}
- message, err := v.EncodeMessage()
+ message, err := v.encodeMessage()
if err != nil {
return err
}
return nil
}
+// encodeMessage encode the verification for the validators to sign or verify
+func (v *Verification) encodeMessage() ([]byte, error) {
+ buff := new(bytes.Buffer)
+ if _, err := v.SourceHash.WriteTo(buff); err != nil {
+ return nil, err
+ }
+
+ if _, err := v.TargetHash.WriteTo(buff); err != nil {
+ return nil, err
+ }
+
+ uint64Buff := make([]byte, 8)
+
+ binary.LittleEndian.PutUint64(uint64Buff, v.SourceHeight)
+ if _, err := buff.Write(uint64Buff); err != nil {
+ return nil, err
+ }
+
+ binary.LittleEndian.PutUint64(uint64Buff, v.TargetHeight)
+ if _, err := buff.Write(uint64Buff); err != nil {
+ return nil, err
+ }
+
+ return sha3Hash(buff.Bytes())
+}
+
func sha3Hash(message []byte) ([]byte, error) {
sha3 := sha3pool.Get256()
defer sha3pool.Put256(sha3)