@ -339,59 +339,13 @@ func (node *Node) BroadcastCXReceipts(newBlock *types.Block) {
func ( node * Node ) VerifyNewBlock ( newBlock * types . Block ) error {
// TODO ek – where do we verify parent-child invariants,
// e.g. "child.Number == child.IsGenesis() ? 0 : parent.Number+1"?
// Verify lastCommitSig
if newBlock . NumberU64 ( ) > 1 {
header := newBlock . Header ( )
parentBlock := node . Blockchain ( ) . GetBlockByNumber ( newBlock . NumberU64 ( ) - 1 )
if parentBlock == nil {
return ctxerror . New ( "[VerifyNewBlock] Failed to get parent block" , "shardID" , header . ShardID , "blockNum" , header . Number )
}
parentHeader := parentBlock . Header ( )
shardState , err := node . Blockchain ( ) . ReadShardState ( parentHeader . Epoch )
committee := shardState . FindCommitteeByID ( parentHeader . ShardID )
if err != nil || committee == nil {
return ctxerror . New ( "[VerifyNewBlock] Failed to read shard state for cross link header" , "shardID" , header . ShardID , "blockNum" , header . Number ) . WithCause ( err )
}
var committerKeys [ ] * bls . PublicKey
parseKeysSuccess := true
for _ , member := range committee . NodeList {
committerKey := new ( bls . PublicKey )
err = member . BlsPublicKey . ToLibBLSPublicKey ( committerKey )
if err != nil {
parseKeysSuccess = false
break
}
committerKeys = append ( committerKeys , committerKey )
}
if ! parseKeysSuccess {
return ctxerror . New ( "[VerifyNewBlock] cannot convert BLS public key" , "shardID" , header . ShardID , "blockNum" , header . Number ) . WithCause ( err )
}
mask , err := bls_cosi . NewMask ( committerKeys , nil )
if err != nil {
return ctxerror . New ( "[VerifyNewBlock] cannot create group sig mask" , "shardID" , header . ShardID , "blockNum" , header . Number ) . WithCause ( err )
}
if err := mask . SetMask ( header . LastCommitBitmap ) ; err != nil {
return ctxerror . New ( "[VerifyNewBlock] cannot set group sig mask bits" , "shardID" , header . ShardID , "blockNum" , header . Number ) . WithCause ( err )
}
aggSig := bls . Sign { }
err = aggSig . Deserialize ( header . LastCommitSignature [ : ] )
if newBlock . NumberU64 ( ) > 1 {
err := node . VerifyBlockLastCommitSigs ( newBlock )
if err != nil {
return ctxerror . New ( "[VerifyNewBlock] unable to deserialize multi-signature from payload" ) . WithCause ( err )
}
blockNumBytes := make ( [ ] byte , 8 )
binary . LittleEndian . PutUint64 ( blockNumBytes , header . Number . Uint64 ( ) - 1 )
commitPayload := append ( blockNumBytes , header . ParentHash [ : ] ... )
if ! aggSig . VerifyHash ( mask . AggregatePublic , commitPayload ) {
return ctxerror . New ( "[VerifyNewBlock] Failed to verify the signature for last commit sig" , "shardID" , header . ShardID , "blockNum" , header . Number )
return err
}
}
// End Verify lastCommitSig
if newBlock . ShardID ( ) != node . Blockchain ( ) . ShardID ( ) {
return ctxerror . New ( "wrong shard ID" ,
"my shard ID" , node . Blockchain ( ) . ShardID ( ) ,
@ -406,63 +360,138 @@ func (node *Node) VerifyNewBlock(newBlock *types.Block) error {
}
// Verify cross links
if node . NodeConfig . ShardID == 0 && len ( newBlock . Header ( ) . CrossLinks ) > 0 {
crossLinks := & types . CrossLinks { }
err := rlp . DecodeBytes ( newBlock . Header ( ) . CrossLinks , crossLinks )
if node . NodeConfig . ShardID == 0 {
err := node . VerifyBlockCrossLinks ( newBlock )
if err != nil {
return ctxerror . New ( "[CrossLinkVerification] failed to decode cross links" ,
"blockHash" , newBlock . Hash ( ) ,
"crossLinks" , len ( newBlock . Header ( ) . CrossLinks ) ,
) . WithCause ( err )
return err
}
for i , crossLink := range * crossLinks {
lastLink := & types . CrossLink { }
if i == 0 {
if crossLink . BlockNum ( ) . Uint64 ( ) > 0 {
lastLink , err = node . Blockchain ( ) . ReadShardLastCrossLink ( crossLink . ShardID ( ) )
if err != nil {
return ctxerror . New ( "[CrossLinkVerification] no last cross link found 1" ,
"blockHash" , newBlock . Hash ( ) ,
"crossLink" , lastLink ,
) . WithCause ( err )
}
} else {
lastLink = & crossLink
}
// TODO: verify the vrf randomness
// _ = newBlock.Header().Vrf
// TODO: uncomment 4 lines after we finish staking mechanism
//err = node.validateNewShardState(newBlock, &node.CurrentStakes)
// if err != nil {
// return ctxerror.New("failed to verify sharding state").WithCause(err)
// }
return nil
}
// VerifyBlockCrossLinks verifies the cross links of the block
func ( node * Node ) VerifyBlockCrossLinks ( block * types . Block ) error {
if len ( block . Header ( ) . CrossLinks ) == 0 {
return nil
}
crossLinks := & types . CrossLinks { }
err := rlp . DecodeBytes ( block . Header ( ) . CrossLinks , crossLinks )
if err != nil {
return ctxerror . New ( "[CrossLinkVerification] failed to decode cross links" ,
"blockHash" , block . Hash ( ) ,
"crossLinks" , len ( block . Header ( ) . CrossLinks ) ,
) . WithCause ( err )
}
if ! crossLinks . IsSorted ( ) {
return ctxerror . New ( "[CrossLinkVerification] cross links are not sorted" ,
"blockHash" , block . Hash ( ) ,
"crossLinks" , len ( block . Header ( ) . CrossLinks ) ,
)
}
firstCrossLinkBlock := core . ShardingSchedule . FirstCrossLinkBlock ( )
for i , crossLink := range * crossLinks {
lastLink := & types . CrossLink { }
if i == 0 {
if crossLink . BlockNum ( ) . Uint64 ( ) > firstCrossLinkBlock {
lastLink , err = node . Blockchain ( ) . ReadShardLastCrossLink ( crossLink . ShardID ( ) )
if err != nil {
return ctxerror . New ( "[CrossLinkVerification] no last cross link found 1" ,
"blockHash" , block . Hash ( ) ,
"crossLink" , lastLink ,
) . WithCause ( err )
}
} else {
if ( * crossLinks ) [ i - 1 ] . Header ( ) . ShardID != crossLink . Header ( ) . ShardID {
}
} else {
if ( * crossLinks ) [ i - 1 ] . Header ( ) . ShardID != crossLink . Header ( ) . ShardID {
if crossLink . BlockNum ( ) . Uint64 ( ) > firstCrossLinkBlock {
lastLink , err = node . Blockchain ( ) . ReadShardLastCrossLink ( crossLink . ShardID ( ) )
if err != nil {
return ctxerror . New ( "[CrossLinkVerification] no last cross link found 2" ,
"blockHash" , newBlock . Hash ( ) ,
"blockHash" , b lock. Hash ( ) ,
"crossLink" , lastLink ,
) . WithCause ( err )
}
} else {
lastLink = & ( * crossLinks ) [ i - 1 ]
}
} else {
lastLink = & ( * crossLinks ) [ i - 1 ]
}
}
if crossLink . BlockNum ( ) . Uint64 ( ) != 0 { // TODO: verify genesis block
err = node . VerifyCrosslinkHeader ( lastLink . Header ( ) , crossLink . Header ( ) )
if err != nil {
return ctxerror . New ( "cannot ValidateNewBlock" ,
"blockHash" , newBlock . Hash ( ) ,
"numTx" , len ( newBlock . Transactions ( ) ) ,
) . WithCause ( err )
}
if crossLink . BlockNum ( ) . Uint64 ( ) > firstCrossLinkBlock { // TODO: verify genesis block
err = node . VerifyCrosslinkHeader ( lastLink . Header ( ) , crossLink . Header ( ) )
if err != nil {
return ctxerror . New ( "cannot ValidateNewBlock" ,
"blockHash" , block . Hash ( ) ,
"numTx" , len ( block . Transactions ( ) ) ,
) . WithCause ( err )
}
}
}
return nil
}
// TODO: verify the vrf randomness
// _ = newBlock.Header().Vrf
// VerifyBlockLastCommitSigs verifies the last commit sigs of the block
func ( node * Node ) VerifyBlockLastCommitSigs ( block * types . Block ) error {
header := block . Header ( )
parentBlock := node . Blockchain ( ) . GetBlockByNumber ( block . NumberU64 ( ) - 1 )
if parentBlock == nil {
return ctxerror . New ( "[VerifyNewBlock] Failed to get parent block" , "shardID" , header . ShardID , "blockNum" , header . Number )
}
parentHeader := parentBlock . Header ( )
shardState , err := node . Blockchain ( ) . ReadShardState ( parentHeader . Epoch )
committee := shardState . FindCommitteeByID ( parentHeader . ShardID )
// TODO: uncomment 4 lines after we finish staking mechanism
//err = node.validateNewShardState(newBlock, &node.CurrentStakes)
// if err != nil {
// return ctxerror.New("failed to verify sharding state").WithCause(err)
// }
if err != nil || committee == nil {
return ctxerror . New ( "[VerifyNewBlock] Failed to read shard state for cross link header" , "shardID" , header . ShardID , "blockNum" , header . Number ) . WithCause ( err )
}
var committerKeys [ ] * bls . PublicKey
parseKeysSuccess := true
for _ , member := range committee . NodeList {
committerKey := new ( bls . PublicKey )
err = member . BlsPublicKey . ToLibBLSPublicKey ( committerKey )
if err != nil {
parseKeysSuccess = false
break
}
committerKeys = append ( committerKeys , committerKey )
}
if ! parseKeysSuccess {
return ctxerror . New ( "[VerifyNewBlock] cannot convert BLS public key" , "shardID" , header . ShardID , "blockNum" , header . Number ) . WithCause ( err )
}
mask , err := bls_cosi . NewMask ( committerKeys , nil )
if err != nil {
return ctxerror . New ( "[VerifyNewBlock] cannot create group sig mask" , "shardID" , header . ShardID , "blockNum" , header . Number ) . WithCause ( err )
}
if err := mask . SetMask ( header . LastCommitBitmap ) ; err != nil {
return ctxerror . New ( "[VerifyNewBlock] cannot set group sig mask bits" , "shardID" , header . ShardID , "blockNum" , header . Number ) . WithCause ( err )
}
aggSig := bls . Sign { }
err = aggSig . Deserialize ( header . LastCommitSignature [ : ] )
if err != nil {
return ctxerror . New ( "[VerifyNewBlock] unable to deserialize multi-signature from payload" ) . WithCause ( err )
}
blockNumBytes := make ( [ ] byte , 8 )
binary . LittleEndian . PutUint64 ( blockNumBytes , header . Number . Uint64 ( ) - 1 )
commitPayload := append ( blockNumBytes , header . ParentHash [ : ] ... )
if ! aggSig . VerifyHash ( mask . AggregatePublic , commitPayload ) {
return ctxerror . New ( "[VerifyNewBlock] Failed to verify the signature for last commit sig" , "shardID" , header . ShardID , "blockNum" , header . Number )
}
return nil
}