mirror of https://github.com/poanetwork/quorum.git
Raft Block Signature (#395)
Added block signature to raft in the header.Extra field
This commit is contained in:
parent
05f6cf9bb2
commit
db8cc814fe
|
@ -3,6 +3,7 @@ package raft
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
@ -32,6 +33,7 @@ type RaftService struct {
|
||||||
// we need an event mux to instantiate the blockchain
|
// we need an event mux to instantiate the blockchain
|
||||||
eventMux *event.TypeMux
|
eventMux *event.TypeMux
|
||||||
minter *minter
|
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) {
|
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(),
|
accountManager: e.AccountManager(),
|
||||||
downloader: e.Downloader(),
|
downloader: e.Downloader(),
|
||||||
startPeers: startPeers,
|
startPeers: startPeers,
|
||||||
|
nodeKey: ctx.NodeKey(),
|
||||||
}
|
}
|
||||||
|
|
||||||
service.minter = newMinter(chainConfig, service, blockTime)
|
service.minter = newMinter(chainConfig, service, blockTime)
|
||||||
|
|
|
@ -25,16 +25,22 @@ import (
|
||||||
|
|
||||||
"github.com/eapache/channels"
|
"github.com/eapache/channels"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"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
|
// Current state information for building the next block
|
||||||
|
@ -50,7 +56,7 @@ type minter struct {
|
||||||
config *params.ChainConfig
|
config *params.ChainConfig
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
mux *event.TypeMux
|
mux *event.TypeMux
|
||||||
eth miner.Backend
|
eth *RaftService
|
||||||
chain *core.BlockChain
|
chain *core.BlockChain
|
||||||
chainDb ethdb.Database
|
chainDb ethdb.Database
|
||||||
coinbase common.Address
|
coinbase common.Address
|
||||||
|
@ -66,6 +72,11 @@ type minter struct {
|
||||||
txPreSub event.Subscription
|
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 {
|
func newMinter(config *params.ChainConfig, eth *RaftService, blockTime time.Duration) *minter {
|
||||||
minter := &minter{
|
minter := &minter{
|
||||||
config: config,
|
config: config,
|
||||||
|
@ -318,8 +329,6 @@ func (minter *minter) mintNewBlock() {
|
||||||
ethash.AccumulateRewards(minter.chain.Config(), work.publicState, header, nil)
|
ethash.AccumulateRewards(minter.chain.Config(), work.publicState, header, nil)
|
||||||
header.Root = work.publicState.IntermediateRoot(minter.chain.Config().IsEIP158(work.header.Number))
|
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...)
|
allReceipts := append(publicReceipts, privateReceipts...)
|
||||||
header.Bloom = types.CreateBloom(allReceipts)
|
header.Bloom = types.CreateBloom(allReceipts)
|
||||||
|
|
||||||
|
@ -330,6 +339,14 @@ func (minter *minter) mintNewBlock() {
|
||||||
l.BlockHash = headerHash
|
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)
|
block := types.NewBlock(header, committedTxes, nil, publicReceipts)
|
||||||
|
|
||||||
log.Info("Generated next block", "block num", block.Number(), "num txes", txCount)
|
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
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -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!")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue