Raft Block Signature (#395)

Added block signature to raft in the header.Extra field
This commit is contained in:
dbryan0516 2018-10-03 20:14:48 -04:00 committed by Samer Falah
parent 05f6cf9bb2
commit db8cc814fe
3 changed files with 119 additions and 4 deletions

View File

@ -3,6 +3,7 @@ package raft
import (
"sync"
"time"
"crypto/ecdsa"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/core"
@ -32,6 +33,7 @@ type RaftService struct {
// we need an event mux to instantiate the blockchain
eventMux *event.TypeMux
minter *minter
nodeKey *ecdsa.PrivateKey
}
func New(ctx *node.ServiceContext, chainConfig *params.ChainConfig, raftId, raftPort uint16, joinExisting bool, blockTime time.Duration, e *eth.Ethereum, startPeers []*discover.Node, datadir string) (*RaftService, error) {
@ -43,6 +45,7 @@ func New(ctx *node.ServiceContext, chainConfig *params.ChainConfig, raftId, raft
accountManager: e.AccountManager(),
downloader: e.Downloader(),
startPeers: startPeers,
nodeKey: ctx.NodeKey(),
}
service.minter = newMinter(chainConfig, service, blockTime)

View File

@ -25,16 +25,22 @@ import (
"github.com/eapache/channels"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
var (
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for arbitrary signer vanity
)
// Current state information for building the next block
@ -50,7 +56,7 @@ type minter struct {
config *params.ChainConfig
mu sync.Mutex
mux *event.TypeMux
eth miner.Backend
eth *RaftService
chain *core.BlockChain
chainDb ethdb.Database
coinbase common.Address
@ -66,6 +72,11 @@ type minter struct {
txPreSub event.Subscription
}
type extraSeal struct {
RaftId []byte // RaftID of the block minter
Signature []byte // Signature of the block minter
}
func newMinter(config *params.ChainConfig, eth *RaftService, blockTime time.Duration) *minter {
minter := &minter{
config: config,
@ -318,8 +329,6 @@ func (minter *minter) mintNewBlock() {
ethash.AccumulateRewards(minter.chain.Config(), work.publicState, header, nil)
header.Root = work.publicState.IntermediateRoot(minter.chain.Config().IsEIP158(work.header.Number))
// NOTE: < QuorumChain creates a signature here and puts it in header.Extra. >
allReceipts := append(publicReceipts, privateReceipts...)
header.Bloom = types.CreateBloom(allReceipts)
@ -330,6 +339,14 @@ func (minter *minter) mintNewBlock() {
l.BlockHash = headerHash
}
//Sign the block and build the extraSeal struct
extraSealBytes := minter.buildExtraSeal(headerHash)
// add vanity and seal to header
// NOTE: leaving vanity blank for now as a space for any future data
header.Extra = make([]byte, extraVanity+len(extraSealBytes))
copy(header.Extra[extraVanity:], extraSealBytes)
block := types.NewBlock(header, committedTxes, nil, publicReceipts)
log.Info("Generated next block", "block num", block.Number(), "num txes", txCount)
@ -407,3 +424,29 @@ func (env *work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, g
return publicReceipt, privateReceipt, nil
}
func (minter *minter) buildExtraSeal(headerHash common.Hash) []byte {
//Sign the headerHash
nodeKey := minter.eth.nodeKey
sig, err := crypto.Sign(headerHash.Bytes(), nodeKey)
if err != nil {
log.Warn("Block sealing failed", "err", err)
}
//build the extraSeal struct
raftIdString := hexutil.EncodeUint64(uint64(minter.eth.raftProtocolManager.raftId))
var extra extraSeal
extra = extraSeal{
RaftId: []byte(raftIdString[2:]), //remove the 0x prefix
Signature: sig,
}
//encode to byte array for storage
extraDataBytes, err := rlp.EncodeToBytes(extra)
if err != nil {
log.Warn("Header.Extra Data Encoding failed", "err", err)
}
return extraDataBytes
}

69
raft/minter_test.go Normal file
View File

@ -0,0 +1,69 @@
package raft
import (
"testing"
"math/big"
"time"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/common/hexutil"
)
func TestSignHeader(t *testing.T){
//create only what we need to test the seal
var testRaftId uint16 = 5
config := &node.Config{Name: "unit-test", DataDir: ""}
nodeKey := config.NodeKey()
raftProtocolManager := &ProtocolManager{raftId:testRaftId}
raftService := &RaftService{nodeKey: nodeKey, raftProtocolManager: raftProtocolManager}
minter := minter{eth: raftService,}
//create some fake header to sign
fakeParentHash := common.HexToHash("0xc2c1dc1be8054808c69e06137429899d")
header := &types.Header{
ParentHash: fakeParentHash,
Number: big.NewInt(1),
Difficulty: big.NewInt(1),
GasLimit: new(big.Int),
GasUsed: new(big.Int),
Coinbase: minter.coinbase,
Time: big.NewInt(time.Now().UnixNano()),
}
headerHash := header.Hash()
extraDataBytes := minter.buildExtraSeal(headerHash)
var seal *extraSeal
err := rlp.DecodeBytes(extraDataBytes[:], &seal)
if err != nil {
t.Fatalf("Unable to decode seal: %s", err.Error())
}
// Check raftId
sealRaftId, err := hexutil.DecodeUint64("0x"+ string(seal.RaftId)) //add the 0x prefix
if err != nil {
t.Errorf("Unable to get RaftId: %s", err.Error())
}
if sealRaftId != uint64(testRaftId) {
t.Errorf("RaftID does not match. Expected: %d, Actual: %d", testRaftId, sealRaftId)
}
//Identify who signed it
sig:= seal.Signature
pubKey, err := crypto.SigToPub(headerHash.Bytes(), sig)
if err != nil {
t.Fatalf("Unable to get public key from signature: %s", err.Error())
}
//Compare derived public key to original public key
if pubKey.X.Cmp(nodeKey.X) != 0 {
t.Errorf("Signature incorrect!")
}
}