mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-27 11:41:39 +00:00
Merge pull request #1667 from tendermint/bucky/abci-11
Update ABCI for new PubKey type and changes to BeginBlock and InitChain
This commit is contained in:
14
Gopkg.lock
generated
14
Gopkg.lock
generated
@ -238,8 +238,8 @@
|
|||||||
"server",
|
"server",
|
||||||
"types"
|
"types"
|
||||||
]
|
]
|
||||||
revision = "78a8905690ef54f9d57e3b2b0ee7ad3a04ef3f1f"
|
revision = "7cf66f570e2f47b286985e2d688b0a400c028e4c"
|
||||||
version = "v0.10.3"
|
version = "v0.11.0-rc6"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@ -263,12 +263,6 @@
|
|||||||
revision = "915416979bf70efa4bcbf1c6cd5d64c5fff9fc19"
|
revision = "915416979bf70efa4bcbf1c6cd5d64c5fff9fc19"
|
||||||
version = "v0.6.2"
|
version = "v0.6.2"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/tendermint/go-wire"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "3c22a7a539411f89a96738fcfa14c1027e24e5ec"
|
|
||||||
version = "0.9.10"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/tendermint/tmlibs"
|
name = "github.com/tendermint/tmlibs"
|
||||||
packages = [
|
packages = [
|
||||||
@ -299,7 +293,7 @@
|
|||||||
"ripemd160",
|
"ripemd160",
|
||||||
"salsa20/salsa"
|
"salsa20/salsa"
|
||||||
]
|
]
|
||||||
revision = "df8d4716b3472e4a531c33cedbe537dae921a1a9"
|
revision = "b47b1587369238182299fe4dad77d05b8b461e06"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@ -380,6 +374,6 @@
|
|||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "bdcf814c0cd3b8d6cc11ad03da556abe169f872a45e6dcbd8b08588b4587ddde"
|
inputs-digest = "132980da98fc92b6c0dd988df07316a340f5fc91ee77593cf984ade4e3e5fd62"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
@ -71,7 +71,7 @@
|
|||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/tendermint/abci"
|
name = "github.com/tendermint/abci"
|
||||||
version = "~0.10.3"
|
version = "~0.11.0-rc6"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/tendermint/go-crypto"
|
name = "github.com/tendermint/go-crypto"
|
||||||
|
@ -58,14 +58,11 @@ func TestByzantine(t *testing.T) {
|
|||||||
css[i].doPrevote = func(height int64, round int) {}
|
css[i].doPrevote = func(height int64, round int) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
eventBus := types.NewEventBus()
|
eventBus := css[i].eventBus
|
||||||
eventBus.SetLogger(logger.With("module", "events", "validator", i))
|
eventBus.SetLogger(logger.With("module", "events", "validator", i))
|
||||||
err := eventBus.Start()
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer eventBus.Stop()
|
|
||||||
|
|
||||||
eventChans[i] = make(chan interface{}, 1)
|
eventChans[i] = make(chan interface{}, 1)
|
||||||
err = eventBus.Subscribe(context.Background(), testSubscriber, types.EventQueryNewBlock, eventChans[i])
|
err := eventBus.Subscribe(context.Background(), testSubscriber, types.EventQueryNewBlock, eventChans[i])
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
conR := NewConsensusReactor(css[i], true) // so we dont start the consensus states
|
conR := NewConsensusReactor(css[i], true) // so we dont start the consensus states
|
||||||
|
@ -254,7 +254,8 @@ func TestReactorVotingPowerChange(t *testing.T) {
|
|||||||
logger.Debug("---------------------------- Testing changing the voting power of one validator a few times")
|
logger.Debug("---------------------------- Testing changing the voting power of one validator a few times")
|
||||||
|
|
||||||
val1PubKey := css[0].privValidator.GetPubKey()
|
val1PubKey := css[0].privValidator.GetPubKey()
|
||||||
updateValidatorTx := kvstore.MakeValSetChangeTx(val1PubKey.Bytes(), 25)
|
val1PubKeyABCI := types.TM2PB.PubKey(val1PubKey)
|
||||||
|
updateValidatorTx := kvstore.MakeValSetChangeTx(val1PubKeyABCI, 25)
|
||||||
previousTotalVotingPower := css[0].GetRoundState().LastValidators.TotalVotingPower()
|
previousTotalVotingPower := css[0].GetRoundState().LastValidators.TotalVotingPower()
|
||||||
|
|
||||||
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx)
|
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx)
|
||||||
@ -266,7 +267,7 @@ func TestReactorVotingPowerChange(t *testing.T) {
|
|||||||
t.Fatalf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[0].GetRoundState().LastValidators.TotalVotingPower())
|
t.Fatalf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[0].GetRoundState().LastValidators.TotalVotingPower())
|
||||||
}
|
}
|
||||||
|
|
||||||
updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKey.Bytes(), 2)
|
updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKeyABCI, 2)
|
||||||
previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower()
|
previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower()
|
||||||
|
|
||||||
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx)
|
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx)
|
||||||
@ -278,7 +279,7 @@ func TestReactorVotingPowerChange(t *testing.T) {
|
|||||||
t.Fatalf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[0].GetRoundState().LastValidators.TotalVotingPower())
|
t.Fatalf("expected voting power to change (before: %d, after: %d)", previousTotalVotingPower, css[0].GetRoundState().LastValidators.TotalVotingPower())
|
||||||
}
|
}
|
||||||
|
|
||||||
updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKey.Bytes(), 26)
|
updateValidatorTx = kvstore.MakeValSetChangeTx(val1PubKeyABCI, 26)
|
||||||
previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower()
|
previousTotalVotingPower = css[0].GetRoundState().LastValidators.TotalVotingPower()
|
||||||
|
|
||||||
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx)
|
waitForAndValidateBlock(t, nVals, activeVals, eventChans, css, updateValidatorTx)
|
||||||
@ -316,7 +317,8 @@ func TestReactorValidatorSetChanges(t *testing.T) {
|
|||||||
logger.Info("---------------------------- Testing adding one validator")
|
logger.Info("---------------------------- Testing adding one validator")
|
||||||
|
|
||||||
newValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
|
newValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
|
||||||
newValidatorTx1 := kvstore.MakeValSetChangeTx(newValidatorPubKey1.Bytes(), testMinPower)
|
valPubKey1ABCI := types.TM2PB.PubKey(newValidatorPubKey1)
|
||||||
|
newValidatorTx1 := kvstore.MakeValSetChangeTx(valPubKey1ABCI, testMinPower)
|
||||||
|
|
||||||
// wait till everyone makes block 2
|
// wait till everyone makes block 2
|
||||||
// ensure the commit includes all validators
|
// ensure the commit includes all validators
|
||||||
@ -342,7 +344,8 @@ func TestReactorValidatorSetChanges(t *testing.T) {
|
|||||||
logger.Info("---------------------------- Testing changing the voting power of one validator")
|
logger.Info("---------------------------- Testing changing the voting power of one validator")
|
||||||
|
|
||||||
updateValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
|
updateValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
|
||||||
updateValidatorTx1 := kvstore.MakeValSetChangeTx(updateValidatorPubKey1.Bytes(), 25)
|
updatePubKey1ABCI := types.TM2PB.PubKey(updateValidatorPubKey1)
|
||||||
|
updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25)
|
||||||
previousTotalVotingPower := css[nVals].GetRoundState().LastValidators.TotalVotingPower()
|
previousTotalVotingPower := css[nVals].GetRoundState().LastValidators.TotalVotingPower()
|
||||||
|
|
||||||
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, updateValidatorTx1)
|
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, updateValidatorTx1)
|
||||||
@ -358,10 +361,12 @@ func TestReactorValidatorSetChanges(t *testing.T) {
|
|||||||
logger.Info("---------------------------- Testing adding two validators at once")
|
logger.Info("---------------------------- Testing adding two validators at once")
|
||||||
|
|
||||||
newValidatorPubKey2 := css[nVals+1].privValidator.GetPubKey()
|
newValidatorPubKey2 := css[nVals+1].privValidator.GetPubKey()
|
||||||
newValidatorTx2 := kvstore.MakeValSetChangeTx(newValidatorPubKey2.Bytes(), testMinPower)
|
newVal2ABCI := types.TM2PB.PubKey(newValidatorPubKey2)
|
||||||
|
newValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, testMinPower)
|
||||||
|
|
||||||
newValidatorPubKey3 := css[nVals+2].privValidator.GetPubKey()
|
newValidatorPubKey3 := css[nVals+2].privValidator.GetPubKey()
|
||||||
newValidatorTx3 := kvstore.MakeValSetChangeTx(newValidatorPubKey3.Bytes(), testMinPower)
|
newVal3ABCI := types.TM2PB.PubKey(newValidatorPubKey3)
|
||||||
|
newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, testMinPower)
|
||||||
|
|
||||||
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, newValidatorTx2, newValidatorTx3)
|
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, newValidatorTx2, newValidatorTx3)
|
||||||
waitForAndValidateBlockWithTx(t, nPeers, activeVals, eventChans, css, newValidatorTx2, newValidatorTx3)
|
waitForAndValidateBlockWithTx(t, nPeers, activeVals, eventChans, css, newValidatorTx2, newValidatorTx3)
|
||||||
@ -373,8 +378,8 @@ func TestReactorValidatorSetChanges(t *testing.T) {
|
|||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
logger.Info("---------------------------- Testing removing two validators at once")
|
logger.Info("---------------------------- Testing removing two validators at once")
|
||||||
|
|
||||||
removeValidatorTx2 := kvstore.MakeValSetChangeTx(newValidatorPubKey2.Bytes(), 0)
|
removeValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, 0)
|
||||||
removeValidatorTx3 := kvstore.MakeValSetChangeTx(newValidatorPubKey3.Bytes(), 0)
|
removeValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 0)
|
||||||
|
|
||||||
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, removeValidatorTx2, removeValidatorTx3)
|
waitForAndValidateBlock(t, nPeers, activeVals, eventChans, css, removeValidatorTx2, removeValidatorTx3)
|
||||||
waitForAndValidateBlockWithTx(t, nPeers, activeVals, eventChans, css, removeValidatorTx2, removeValidatorTx3)
|
waitForAndValidateBlockWithTx(t, nPeers, activeVals, eventChans, css, removeValidatorTx2, removeValidatorTx3)
|
||||||
|
@ -2,7 +2,6 @@ package consensus
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
@ -197,20 +196,20 @@ type Handshaker struct {
|
|||||||
stateDB dbm.DB
|
stateDB dbm.DB
|
||||||
initialState sm.State
|
initialState sm.State
|
||||||
store sm.BlockStore
|
store sm.BlockStore
|
||||||
appState json.RawMessage
|
genDoc *types.GenesisDoc
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
|
|
||||||
nBlocks int // number of blocks applied to the state
|
nBlocks int // number of blocks applied to the state
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandshaker(stateDB dbm.DB, state sm.State,
|
func NewHandshaker(stateDB dbm.DB, state sm.State,
|
||||||
store sm.BlockStore, appState json.RawMessage) *Handshaker {
|
store sm.BlockStore, genDoc *types.GenesisDoc) *Handshaker {
|
||||||
|
|
||||||
return &Handshaker{
|
return &Handshaker{
|
||||||
stateDB: stateDB,
|
stateDB: stateDB,
|
||||||
initialState: state,
|
initialState: state,
|
||||||
store: store,
|
store: store,
|
||||||
appState: appState,
|
genDoc: genDoc,
|
||||||
logger: log.NewNopLogger(),
|
logger: log.NewNopLogger(),
|
||||||
nBlocks: 0,
|
nBlocks: 0,
|
||||||
}
|
}
|
||||||
@ -269,8 +268,11 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight
|
|||||||
if appBlockHeight == 0 {
|
if appBlockHeight == 0 {
|
||||||
validators := types.TM2PB.Validators(state.Validators)
|
validators := types.TM2PB.Validators(state.Validators)
|
||||||
req := abci.RequestInitChain{
|
req := abci.RequestInitChain{
|
||||||
|
Time: h.genDoc.GenesisTime.Unix(), // TODO
|
||||||
|
ChainId: h.genDoc.ChainID,
|
||||||
|
ConsensusParams: types.TM2PB.ConsensusParams(h.genDoc.ConsensusParams),
|
||||||
Validators: validators,
|
Validators: validators,
|
||||||
AppStateBytes: h.appState,
|
AppStateBytes: h.genDoc.AppStateJSON,
|
||||||
}
|
}
|
||||||
_, err := proxyApp.Consensus().InitChainSync(req)
|
_, err := proxyApp.Consensus().InitChainSync(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -365,7 +367,7 @@ func (h *Handshaker) replayBlocks(state sm.State, proxyApp proxy.AppConns, appBl
|
|||||||
for i := appBlockHeight + 1; i <= finalBlock; i++ {
|
for i := appBlockHeight + 1; i <= finalBlock; i++ {
|
||||||
h.logger.Info("Applying block", "height", i)
|
h.logger.Info("Applying block", "height", i)
|
||||||
block := h.store.LoadBlock(i)
|
block := h.store.LoadBlock(i)
|
||||||
appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, h.logger)
|
appHash, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, h.logger, state.LastValidators, h.stateDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -299,7 +299,7 @@ func newConsensusStateForReplay(config cfg.BaseConfig, csConfig *cfg.ConsensusCo
|
|||||||
// Create proxyAppConn connection (consensus, mempool, query)
|
// Create proxyAppConn connection (consensus, mempool, query)
|
||||||
clientCreator := proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir())
|
clientCreator := proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir())
|
||||||
proxyApp := proxy.NewAppConns(clientCreator,
|
proxyApp := proxy.NewAppConns(clientCreator,
|
||||||
NewHandshaker(stateDB, state, blockStore, gdoc.AppState()))
|
NewHandshaker(stateDB, state, blockStore, gdoc))
|
||||||
err = proxyApp.Start()
|
err = proxyApp.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmn.Exit(cmn.Fmt("Error starting proxy app conns: %v", err))
|
cmn.Exit(cmn.Fmt("Error starting proxy app conns: %v", err))
|
||||||
|
@ -366,7 +366,8 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// now start the app using the handshake - it should sync
|
// now start the app using the handshake - it should sync
|
||||||
handshaker := NewHandshaker(stateDB, state, store, nil)
|
genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile())
|
||||||
|
handshaker := NewHandshaker(stateDB, state, store, genDoc)
|
||||||
proxyApp := proxy.NewAppConns(clientCreator2, handshaker)
|
proxyApp := proxy.NewAppConns(clientCreator2, handshaker)
|
||||||
if err := proxyApp.Start(); err != nil {
|
if err := proxyApp.Start(); err != nil {
|
||||||
t.Fatalf("Error starting proxy app connections: %v", err)
|
t.Fatalf("Error starting proxy app connections: %v", err)
|
||||||
@ -416,10 +417,10 @@ func buildAppStateFromChain(proxyApp proxy.AppConns, stateDB dbm.DB,
|
|||||||
}
|
}
|
||||||
defer proxyApp.Stop()
|
defer proxyApp.Stop()
|
||||||
|
|
||||||
// TODO: get the genesis bytes (https://github.com/tendermint/tendermint/issues/1224)
|
|
||||||
var genesisBytes []byte
|
|
||||||
validators := types.TM2PB.Validators(state.Validators)
|
validators := types.TM2PB.Validators(state.Validators)
|
||||||
if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{validators, genesisBytes}); err != nil {
|
if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{
|
||||||
|
Validators: validators,
|
||||||
|
}); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,10 +454,10 @@ func buildTMStateFromChain(config *cfg.Config, stateDB dbm.DB, state sm.State, c
|
|||||||
}
|
}
|
||||||
defer proxyApp.Stop()
|
defer proxyApp.Stop()
|
||||||
|
|
||||||
// TODO: get the genesis bytes (https://github.com/tendermint/tendermint/issues/1224)
|
|
||||||
var genesisBytes []byte
|
|
||||||
validators := types.TM2PB.Validators(state.Validators)
|
validators := types.TM2PB.Validators(state.Validators)
|
||||||
if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{validators, genesisBytes}); err != nil {
|
if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{
|
||||||
|
Validators: validators,
|
||||||
|
}); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ func WALWithNBlocks(numBlocks int) (data []byte, err error) {
|
|||||||
return nil, errors.Wrap(err, "failed to make genesis state")
|
return nil, errors.Wrap(err, "failed to make genesis state")
|
||||||
}
|
}
|
||||||
blockStore := bc.NewBlockStore(blockStoreDB)
|
blockStore := bc.NewBlockStore(blockStoreDB)
|
||||||
handshaker := NewHandshaker(stateDB, state, blockStore, genDoc.AppState())
|
handshaker := NewHandshaker(stateDB, state, blockStore, genDoc)
|
||||||
proxyApp := proxy.NewAppConns(proxy.NewLocalClientCreator(app), handshaker)
|
proxyApp := proxy.NewAppConns(proxy.NewLocalClientCreator(app), handshaker)
|
||||||
proxyApp.SetLogger(logger.With("module", "proxy"))
|
proxyApp.SetLogger(logger.With("module", "proxy"))
|
||||||
if err := proxyApp.Start(); err != nil {
|
if err := proxyApp.Start(); err != nil {
|
||||||
|
@ -159,7 +159,7 @@ func NewNode(config *cfg.Config,
|
|||||||
// and sync tendermint and the app by performing a handshake
|
// and sync tendermint and the app by performing a handshake
|
||||||
// and replaying any necessary blocks
|
// and replaying any necessary blocks
|
||||||
consensusLogger := logger.With("module", "consensus")
|
consensusLogger := logger.With("module", "consensus")
|
||||||
handshaker := cs.NewHandshaker(stateDB, state, blockStore, genDoc.AppState())
|
handshaker := cs.NewHandshaker(stateDB, state, blockStore, genDoc)
|
||||||
handshaker.SetLogger(consensusLogger)
|
handshaker.SetLogger(consensusLogger)
|
||||||
proxyApp := proxy.NewAppConns(clientCreator, handshaker)
|
proxyApp := proxy.NewAppConns(clientCreator, handshaker)
|
||||||
proxyApp.SetLogger(logger.With("module", "proxy"))
|
proxyApp.SetLogger(logger.With("module", "proxy"))
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
|
|
||||||
fail "github.com/ebuchman/fail-test"
|
fail "github.com/ebuchman/fail-test"
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
crypto "github.com/tendermint/go-crypto"
|
|
||||||
"github.com/tendermint/tendermint/proxy"
|
"github.com/tendermint/tendermint/proxy"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
@ -74,7 +73,7 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b
|
|||||||
return state, ErrInvalidBlock(err)
|
return state, ErrInvalidBlock(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block)
|
abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, state.LastValidators, blockExec.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return state, ErrProxyAppConn(err)
|
return state, ErrProxyAppConn(err)
|
||||||
}
|
}
|
||||||
@ -158,7 +157,8 @@ func (blockExec *BlockExecutor) Commit(block *types.Block) ([]byte, error) {
|
|||||||
|
|
||||||
// Executes block's transactions on proxyAppConn.
|
// Executes block's transactions on proxyAppConn.
|
||||||
// Returns a list of transaction results and updates to the validator set
|
// Returns a list of transaction results and updates to the validator set
|
||||||
func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus, block *types.Block) (*ABCIResponses, error) {
|
func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
||||||
|
block *types.Block, lastValSet *types.ValidatorSet, stateDB dbm.DB) (*ABCIResponses, error) {
|
||||||
var validTxs, invalidTxs = 0, 0
|
var validTxs, invalidTxs = 0, 0
|
||||||
|
|
||||||
txIndex := 0
|
txIndex := 0
|
||||||
@ -184,29 +184,14 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
|||||||
}
|
}
|
||||||
proxyAppConn.SetResponseCallback(proxyCb)
|
proxyAppConn.SetResponseCallback(proxyCb)
|
||||||
|
|
||||||
// determine which validators did not sign last block
|
signVals, byzVals := getBeginBlockValidatorInfo(block, lastValSet, stateDB)
|
||||||
absentVals := make([]int32, 0)
|
|
||||||
for valI, vote := range block.LastCommit.Precommits {
|
|
||||||
if vote == nil {
|
|
||||||
absentVals = append(absentVals, int32(valI))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: determine which validators were byzantine
|
|
||||||
byzantineVals := make([]abci.Evidence, len(block.Evidence.Evidence))
|
|
||||||
for i, ev := range block.Evidence.Evidence {
|
|
||||||
byzantineVals[i] = abci.Evidence{
|
|
||||||
PubKey: ev.Address(), // XXX
|
|
||||||
Height: ev.Height(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin block
|
// Begin block
|
||||||
_, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
|
_, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
|
||||||
Hash: block.Hash(),
|
Hash: block.Hash(),
|
||||||
Header: types.TM2PB.Header(block.Header),
|
Header: types.TM2PB.Header(block.Header),
|
||||||
AbsentValidators: absentVals,
|
Validators: signVals,
|
||||||
ByzantineValidators: byzantineVals,
|
ByzantineValidators: byzVals,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error in proxyAppConn.BeginBlock", "err", err)
|
logger.Error("Error in proxyAppConn.BeginBlock", "err", err)
|
||||||
@ -238,12 +223,56 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
|||||||
return abciResponses, nil
|
return abciResponses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getBeginBlockValidatorInfo(block *types.Block, lastValSet *types.ValidatorSet, stateDB dbm.DB) ([]abci.SigningValidator, []abci.Evidence) {
|
||||||
|
|
||||||
|
// Sanity check that commit length matches validator set size -
|
||||||
|
// only applies after first block
|
||||||
|
if block.Height > 1 {
|
||||||
|
precommitLen := len(block.LastCommit.Precommits)
|
||||||
|
valSetLen := len(lastValSet.Validators)
|
||||||
|
if precommitLen != valSetLen {
|
||||||
|
// sanity check
|
||||||
|
panic(fmt.Sprintf("precommit length (%d) doesn't match valset length (%d) at height %d\n\n%v\n\n%v",
|
||||||
|
precommitLen, valSetLen, block.Height, block.LastCommit.Precommits, lastValSet.Validators))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine which validators did not sign last block.
|
||||||
|
signVals := make([]abci.SigningValidator, len(lastValSet.Validators))
|
||||||
|
for i, val := range lastValSet.Validators {
|
||||||
|
var vote *types.Vote
|
||||||
|
if i < len(block.LastCommit.Precommits) {
|
||||||
|
vote = block.LastCommit.Precommits[i]
|
||||||
|
}
|
||||||
|
val := abci.SigningValidator{
|
||||||
|
Validator: types.TM2PB.Validator(val),
|
||||||
|
SignedLastBlock: vote != nil,
|
||||||
|
}
|
||||||
|
signVals[i] = val
|
||||||
|
}
|
||||||
|
|
||||||
|
byzVals := make([]abci.Evidence, len(block.Evidence.Evidence))
|
||||||
|
for i, ev := range block.Evidence.Evidence {
|
||||||
|
// We need the validator set. We already did this in validateBlock.
|
||||||
|
// TODO: Should we instead cache the valset in the evidence itself and add
|
||||||
|
// `SetValidatorSet()` and `ToABCI` methods ?
|
||||||
|
valset, err := LoadValidators(stateDB, ev.Height())
|
||||||
|
if err != nil {
|
||||||
|
panic(err) // shouldn't happen
|
||||||
|
}
|
||||||
|
byzVals[i] = types.TM2PB.Evidence(ev, valset, block.Time)
|
||||||
|
}
|
||||||
|
|
||||||
|
return signVals, byzVals
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// If more or equal than 1/3 of total voting power changed in one block, then
|
// If more or equal than 1/3 of total voting power changed in one block, then
|
||||||
// a light client could never prove the transition externally. See
|
// a light client could never prove the transition externally. See
|
||||||
// ./lite/doc.go for details on how a light client tracks validators.
|
// ./lite/doc.go for details on how a light client tracks validators.
|
||||||
func updateValidators(currentSet *types.ValidatorSet, updates []abci.Validator) error {
|
func updateValidators(currentSet *types.ValidatorSet, updates []abci.Validator) error {
|
||||||
for _, v := range updates {
|
for _, v := range updates {
|
||||||
pubkey, err := crypto.PubKeyFromBytes(v.PubKey) // NOTE: expects go-amino encoded pubkey
|
pubkey, err := types.PB2TM.PubKey(v.PubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -357,8 +386,9 @@ func fireEvents(logger log.Logger, eventBus types.BlockEventPublisher, block *ty
|
|||||||
|
|
||||||
// ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state.
|
// ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state.
|
||||||
// It returns the application root hash (result of abci.Commit).
|
// It returns the application root hash (result of abci.Commit).
|
||||||
func ExecCommitBlock(appConnConsensus proxy.AppConnConsensus, block *types.Block, logger log.Logger) ([]byte, error) {
|
func ExecCommitBlock(appConnConsensus proxy.AppConnConsensus, block *types.Block,
|
||||||
_, err := execBlockOnProxyApp(logger, appConnConsensus, block)
|
logger log.Logger, lastValSet *types.ValidatorSet, stateDB dbm.DB) ([]byte, error) {
|
||||||
|
_, err := execBlockOnProxyApp(logger, appConnConsensus, block, lastValSet, stateDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error executing block on proxy app", "height", block.Height, "err", err)
|
logger.Error("Error executing block on proxy app", "height", block.Height, "err", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -19,7 +20,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
privKey = crypto.GenPrivKeyEd25519FromSecret([]byte("execution_test"))
|
|
||||||
chainID = "execution_chain"
|
chainID = "execution_chain"
|
||||||
testPartSize = 65536
|
testPartSize = 65536
|
||||||
nTxsPerBlock = 10
|
nTxsPerBlock = 10
|
||||||
@ -32,7 +32,7 @@ func TestApplyBlock(t *testing.T) {
|
|||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
defer proxyApp.Stop()
|
defer proxyApp.Stop()
|
||||||
|
|
||||||
state, stateDB := state(), dbm.NewMemDB()
|
state, stateDB := state(1, 1)
|
||||||
|
|
||||||
blockExec := NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(),
|
blockExec := NewBlockExecutor(stateDB, log.TestingLogger(), proxyApp.Consensus(),
|
||||||
MockMempool{}, MockEvidencePool{})
|
MockMempool{}, MockEvidencePool{})
|
||||||
@ -46,8 +46,8 @@ func TestApplyBlock(t *testing.T) {
|
|||||||
// TODO check state and mempool
|
// TODO check state and mempool
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestBeginBlockAbsentValidators ensures we send absent validators list.
|
// TestBeginBlockValidators ensures we send absent validators list.
|
||||||
func TestBeginBlockAbsentValidators(t *testing.T) {
|
func TestBeginBlockValidators(t *testing.T) {
|
||||||
app := &testApp{}
|
app := &testApp{}
|
||||||
cc := proxy.NewLocalClientCreator(app)
|
cc := proxy.NewLocalClientCreator(app)
|
||||||
proxyApp := proxy.NewAppConns(cc, nil)
|
proxyApp := proxy.NewAppConns(cc, nil)
|
||||||
@ -55,32 +55,46 @@ func TestBeginBlockAbsentValidators(t *testing.T) {
|
|||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
defer proxyApp.Stop()
|
defer proxyApp.Stop()
|
||||||
|
|
||||||
state := state()
|
state, stateDB := state(2, 2)
|
||||||
|
|
||||||
prevHash := state.LastBlockID.Hash
|
prevHash := state.LastBlockID.Hash
|
||||||
prevParts := types.PartSetHeader{}
|
prevParts := types.PartSetHeader{}
|
||||||
prevBlockID := types.BlockID{prevHash, prevParts}
|
prevBlockID := types.BlockID{prevHash, prevParts}
|
||||||
|
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
|
vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}
|
||||||
|
vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
lastCommitPrecommits []*types.Vote
|
lastCommitPrecommits []*types.Vote
|
||||||
expectedAbsentValidators []int32
|
expectedAbsentValidators []int
|
||||||
}{
|
}{
|
||||||
{"none absent", []*types.Vote{{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}, {ValidatorIndex: 1, Timestamp: now}}, []int32{}},
|
{"none absent", []*types.Vote{vote0, vote1}, []int{}},
|
||||||
{"one absent", []*types.Vote{{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}, nil}, []int32{1}},
|
{"one absent", []*types.Vote{vote0, nil}, []int{1}},
|
||||||
{"multiple absent", []*types.Vote{nil, nil}, []int32{0, 1}},
|
{"multiple absent", []*types.Vote{nil, nil}, []int{0, 1}},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: tc.lastCommitPrecommits}
|
lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: tc.lastCommitPrecommits}
|
||||||
|
|
||||||
|
// block for height 2
|
||||||
block, _ := state.MakeBlock(2, makeTxs(2), lastCommit)
|
block, _ := state.MakeBlock(2, makeTxs(2), lastCommit)
|
||||||
_, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger())
|
_, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators, stateDB)
|
||||||
require.Nil(t, err, tc.desc)
|
require.Nil(t, err, tc.desc)
|
||||||
|
|
||||||
// -> app must receive an index of the absent validator
|
// -> app receives a list of validators with a bool indicating if they signed
|
||||||
assert.Equal(t, tc.expectedAbsentValidators, app.AbsentValidators, tc.desc)
|
ctr := 0
|
||||||
|
for i, v := range app.Validators {
|
||||||
|
if ctr < len(tc.expectedAbsentValidators) &&
|
||||||
|
tc.expectedAbsentValidators[ctr] == i {
|
||||||
|
|
||||||
|
assert.False(t, v.SignedLastBlock)
|
||||||
|
ctr++
|
||||||
|
} else {
|
||||||
|
assert.True(t, v.SignedLastBlock)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,35 +107,41 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
|
|||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
defer proxyApp.Stop()
|
defer proxyApp.Stop()
|
||||||
|
|
||||||
state := state()
|
state, stateDB := state(2, 12)
|
||||||
|
|
||||||
prevHash := state.LastBlockID.Hash
|
prevHash := state.LastBlockID.Hash
|
||||||
prevParts := types.PartSetHeader{}
|
prevParts := types.PartSetHeader{}
|
||||||
prevBlockID := types.BlockID{prevHash, prevParts}
|
prevBlockID := types.BlockID{prevHash, prevParts}
|
||||||
|
|
||||||
height1, idx1, val1 := int64(8), 0, []byte("val1")
|
height1, idx1, val1 := int64(8), 0, state.Validators.Validators[0].Address
|
||||||
height2, idx2, val2 := int64(3), 1, []byte("val2")
|
height2, idx2, val2 := int64(3), 1, state.Validators.Validators[1].Address
|
||||||
ev1 := types.NewMockGoodEvidence(height1, idx1, val1)
|
ev1 := types.NewMockGoodEvidence(height1, idx1, val1)
|
||||||
ev2 := types.NewMockGoodEvidence(height2, idx2, val2)
|
ev2 := types.NewMockGoodEvidence(height2, idx2, val2)
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
valSet := state.Validators
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
evidence []types.Evidence
|
evidence []types.Evidence
|
||||||
expectedByzantineValidators []abci.Evidence
|
expectedByzantineValidators []abci.Evidence
|
||||||
}{
|
}{
|
||||||
{"none byzantine", []types.Evidence{}, []abci.Evidence{}},
|
{"none byzantine", []types.Evidence{}, []abci.Evidence{}},
|
||||||
{"one byzantine", []types.Evidence{ev1}, []abci.Evidence{{ev1.Address(), ev1.Height()}}},
|
{"one byzantine", []types.Evidence{ev1}, []abci.Evidence{types.TM2PB.Evidence(ev1, valSet, now)}},
|
||||||
{"multiple byzantine", []types.Evidence{ev1, ev2}, []abci.Evidence{
|
{"multiple byzantine", []types.Evidence{ev1, ev2}, []abci.Evidence{
|
||||||
{ev1.Address(), ev1.Height()},
|
types.TM2PB.Evidence(ev1, valSet, now),
|
||||||
{ev2.Address(), ev2.Height()}}},
|
types.TM2PB.Evidence(ev2, valSet, now)}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}
|
||||||
|
vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now}
|
||||||
|
votes := []*types.Vote{vote0, vote1}
|
||||||
|
lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: votes}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
lastCommit := &types.Commit{BlockID: prevBlockID}
|
|
||||||
|
|
||||||
block, _ := state.MakeBlock(10, makeTxs(2), lastCommit)
|
block, _ := state.MakeBlock(10, makeTxs(2), lastCommit)
|
||||||
|
block.Time = now
|
||||||
block.Evidence.Evidence = tc.evidence
|
block.Evidence.Evidence = tc.evidence
|
||||||
_, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger())
|
_, err = ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), state.Validators, stateDB)
|
||||||
require.Nil(t, err, tc.desc)
|
require.Nil(t, err, tc.desc)
|
||||||
|
|
||||||
// -> app must receive an index of the byzantine validator
|
// -> app must receive an index of the byzantine validator
|
||||||
@ -139,15 +159,30 @@ func makeTxs(height int64) (txs []types.Tx) {
|
|||||||
return txs
|
return txs
|
||||||
}
|
}
|
||||||
|
|
||||||
func state() State {
|
func state(nVals, height int) (State, dbm.DB) {
|
||||||
|
vals := make([]types.GenesisValidator, nVals)
|
||||||
|
for i := 0; i < nVals; i++ {
|
||||||
|
secret := []byte(fmt.Sprintf("test%d", i))
|
||||||
|
pk := crypto.GenPrivKeyEd25519FromSecret(secret)
|
||||||
|
vals[i] = types.GenesisValidator{
|
||||||
|
pk.PubKey(), 1000, fmt.Sprintf("test%d", i),
|
||||||
|
}
|
||||||
|
}
|
||||||
s, _ := MakeGenesisState(&types.GenesisDoc{
|
s, _ := MakeGenesisState(&types.GenesisDoc{
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
Validators: []types.GenesisValidator{
|
Validators: vals,
|
||||||
{privKey.PubKey(), 10000, "test"},
|
|
||||||
},
|
|
||||||
AppHash: nil,
|
AppHash: nil,
|
||||||
})
|
})
|
||||||
return s
|
|
||||||
|
// save validators to db for 2 heights
|
||||||
|
stateDB := dbm.NewMemDB()
|
||||||
|
SaveState(stateDB, s)
|
||||||
|
|
||||||
|
for i := 1; i < height; i++ {
|
||||||
|
s.LastBlockHeight += 1
|
||||||
|
SaveState(stateDB, s)
|
||||||
|
}
|
||||||
|
return s, stateDB
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeBlock(state State, height int64) *types.Block {
|
func makeBlock(state State, height int64) *types.Block {
|
||||||
@ -162,7 +197,7 @@ var _ abci.Application = (*testApp)(nil)
|
|||||||
type testApp struct {
|
type testApp struct {
|
||||||
abci.BaseApplication
|
abci.BaseApplication
|
||||||
|
|
||||||
AbsentValidators []int32
|
Validators []abci.SigningValidator
|
||||||
ByzantineValidators []abci.Evidence
|
ByzantineValidators []abci.Evidence
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +210,7 @@ func (app *testApp) Info(req abci.RequestInfo) (resInfo abci.ResponseInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (app *testApp) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock {
|
func (app *testApp) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock {
|
||||||
app.AbsentValidators = req.AbsentValidators
|
app.Validators = req.Validators
|
||||||
app.ByzantineValidators = req.ByzantineValidators
|
app.ByzantineValidators = req.ByzantineValidators
|
||||||
return abci.ResponseBeginBlock{}
|
return abci.ResponseBeginBlock{}
|
||||||
}
|
}
|
||||||
|
@ -78,10 +78,7 @@ func TestABCIResponsesSaveLoad1(t *testing.T) {
|
|||||||
abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Tags: nil}
|
abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Tags: nil}
|
||||||
abciResponses.DeliverTx[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Tags: nil}
|
abciResponses.DeliverTx[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Tags: nil}
|
||||||
abciResponses.EndBlock = &abci.ResponseEndBlock{ValidatorUpdates: []abci.Validator{
|
abciResponses.EndBlock = &abci.ResponseEndBlock{ValidatorUpdates: []abci.Validator{
|
||||||
{
|
types.TM2PB.ValidatorFromPubKeyAndPower(crypto.GenPrivKeyEd25519().PubKey(), 10),
|
||||||
PubKey: crypto.GenPrivKeyEd25519().PubKey().Bytes(),
|
|
||||||
Power: 10,
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
saveABCIResponses(stateDB, block.Height, abciResponses)
|
saveABCIResponses(stateDB, block.Height, abciResponses)
|
||||||
@ -435,8 +432,8 @@ func makeHeaderPartsResponsesValPubKeyChange(state State, height int64,
|
|||||||
if !bytes.Equal(pubkey.Bytes(), val.PubKey.Bytes()) {
|
if !bytes.Equal(pubkey.Bytes(), val.PubKey.Bytes()) {
|
||||||
abciResponses.EndBlock = &abci.ResponseEndBlock{
|
abciResponses.EndBlock = &abci.ResponseEndBlock{
|
||||||
ValidatorUpdates: []abci.Validator{
|
ValidatorUpdates: []abci.Validator{
|
||||||
{val.PubKey.Bytes(), 0},
|
types.TM2PB.ValidatorFromPubKeyAndPower(val.PubKey, 0),
|
||||||
{pubkey.Bytes(), 10},
|
types.TM2PB.ValidatorFromPubKeyAndPower(pubkey, 10),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -457,7 +454,7 @@ func makeHeaderPartsResponsesValPowerChange(state State, height int64,
|
|||||||
if val.VotingPower != power {
|
if val.VotingPower != power {
|
||||||
abciResponses.EndBlock = &abci.ResponseEndBlock{
|
abciResponses.EndBlock = &abci.ResponseEndBlock{
|
||||||
ValidatorUpdates: []abci.Validator{
|
ValidatorUpdates: []abci.Validator{
|
||||||
{val.PubKey.Bytes(), power},
|
types.TM2PB.ValidatorFromPubKeyAndPower(val.PubKey, power),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,11 +173,12 @@ func LoadValidators(db dbm.DB, height int64) (*types.ValidatorSet, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if valInfo.ValidatorSet == nil {
|
if valInfo.ValidatorSet == nil {
|
||||||
valInfo = loadValidatorsInfo(db, valInfo.LastHeightChanged)
|
valInfo2 := loadValidatorsInfo(db, valInfo.LastHeightChanged)
|
||||||
if valInfo == nil {
|
if valInfo2 == nil {
|
||||||
cmn.PanicSanity(fmt.Sprintf(`Couldn't find validators at height %d as
|
cmn.PanicSanity(fmt.Sprintf(`Couldn't find validators at height %d as
|
||||||
last changed from height %d`, valInfo.LastHeightChanged, height))
|
last changed from height %d`, valInfo.LastHeightChanged, height))
|
||||||
}
|
}
|
||||||
|
valInfo = valInfo2
|
||||||
}
|
}
|
||||||
|
|
||||||
return valInfo.ValidatorSet, nil
|
return valInfo.ValidatorSet, nil
|
||||||
|
@ -73,6 +73,9 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Each check requires loading an old validator set.
|
||||||
|
// We should cap the amount of evidence per block
|
||||||
|
// to prevent potential proposer DoS.
|
||||||
for _, ev := range block.Evidence.Evidence {
|
for _, ev := range block.Evidence.Evidence {
|
||||||
if err := VerifyEvidence(stateDB, state, ev); err != nil {
|
if err := VerifyEvidence(stateDB, state, ev); err != nil {
|
||||||
return types.NewEvidenceInvalidErr(ev, err)
|
return types.NewEvidenceInvalidErr(ev, err)
|
||||||
@ -82,11 +85,11 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: What's cheaper (ie. what should be checked first):
|
// VerifyEvidence verifies the evidence fully by checking:
|
||||||
// evidence internal validity (ie. sig checks) or validator existed (fetch historical val set from db)
|
// - it is sufficiently recent (MaxAge)
|
||||||
|
// - it is from a key who was a validator at the given height
|
||||||
// VerifyEvidence verifies the evidence fully by checking it is internally
|
// - it is internally consistent
|
||||||
// consistent and sufficiently recent.
|
// - it was properly signed by the alleged equivocator
|
||||||
func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error {
|
func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error {
|
||||||
height := state.LastBlockHeight
|
height := state.LastBlockHeight
|
||||||
|
|
||||||
@ -97,10 +100,6 @@ func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error
|
|||||||
evidence.Height(), height-maxAge)
|
evidence.Height(), height-maxAge)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := evidence.Verify(state.ChainID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
valset, err := LoadValidators(stateDB, evidence.Height())
|
valset, err := LoadValidators(stateDB, evidence.Height())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: if err is just that we cant find it cuz we pruned, ignore.
|
// TODO: if err is just that we cant find it cuz we pruned, ignore.
|
||||||
@ -108,14 +107,18 @@ func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// The address must have been an active validator at the height
|
// The address must have been an active validator at the height.
|
||||||
|
// NOTE: we will ignore evidence from H if the key was not a validator
|
||||||
|
// at H, even if it is a validator at some nearby H'
|
||||||
ev := evidence
|
ev := evidence
|
||||||
height, addr, idx := ev.Height(), ev.Address(), ev.Index()
|
height, addr := ev.Height(), ev.Address()
|
||||||
valIdx, val := valset.GetByAddress(addr)
|
_, val := valset.GetByAddress(addr)
|
||||||
if val == nil {
|
if val == nil {
|
||||||
return fmt.Errorf("Address %X was not a validator at height %d", addr, height)
|
return fmt.Errorf("Address %X was not a validator at height %d", addr, height)
|
||||||
} else if idx != valIdx {
|
}
|
||||||
return fmt.Errorf("Address %X was validator %d at height %d, not %d", addr, valIdx, height, idx)
|
|
||||||
|
if err := evidence.Verify(state.ChainID, val.PubKey); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestValidateBlock(t *testing.T) {
|
func TestValidateBlock(t *testing.T) {
|
||||||
state := state()
|
state, _ := state(1, 1)
|
||||||
|
|
||||||
blockExec := NewBlockExecutor(dbm.NewMemDB(), log.TestingLogger(), nil, nil, nil)
|
blockExec := NewBlockExecutor(dbm.NewMemDB(), log.TestingLogger(), nil, nil, nil)
|
||||||
|
|
||||||
|
@ -30,9 +30,8 @@ func (err *ErrEvidenceInvalid) Error() string {
|
|||||||
type Evidence interface {
|
type Evidence interface {
|
||||||
Height() int64 // height of the equivocation
|
Height() int64 // height of the equivocation
|
||||||
Address() []byte // address of the equivocating validator
|
Address() []byte // address of the equivocating validator
|
||||||
Index() int // index of the validator in the validator set
|
|
||||||
Hash() []byte // hash of the evidence
|
Hash() []byte // hash of the evidence
|
||||||
Verify(chainID string) error // verify the evidence
|
Verify(chainID string, pubKey crypto.PubKey) error // verify the evidence
|
||||||
Equal(Evidence) bool // check equality of evidence
|
Equal(Evidence) bool // check equality of evidence
|
||||||
|
|
||||||
String() string
|
String() string
|
||||||
@ -68,11 +67,6 @@ func (dve *DuplicateVoteEvidence) Address() []byte {
|
|||||||
return dve.PubKey.Address()
|
return dve.PubKey.Address()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Index returns the index of the validator.
|
|
||||||
func (dve *DuplicateVoteEvidence) Index() int {
|
|
||||||
return dve.VoteA.ValidatorIndex
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns the hash of the evidence.
|
// Hash returns the hash of the evidence.
|
||||||
func (dve *DuplicateVoteEvidence) Hash() []byte {
|
func (dve *DuplicateVoteEvidence) Hash() []byte {
|
||||||
return aminoHasher(dve).Hash()
|
return aminoHasher(dve).Hash()
|
||||||
@ -80,7 +74,7 @@ func (dve *DuplicateVoteEvidence) Hash() []byte {
|
|||||||
|
|
||||||
// Verify returns an error if the two votes aren't conflicting.
|
// Verify returns an error if the two votes aren't conflicting.
|
||||||
// To be conflicting, they must be from the same validator, for the same H/R/S, but for different blocks.
|
// To be conflicting, they must be from the same validator, for the same H/R/S, but for different blocks.
|
||||||
func (dve *DuplicateVoteEvidence) Verify(chainID string) error {
|
func (dve *DuplicateVoteEvidence) Verify(chainID string, pubKey crypto.PubKey) error {
|
||||||
// H/R/S must be the same
|
// H/R/S must be the same
|
||||||
if dve.VoteA.Height != dve.VoteB.Height ||
|
if dve.VoteA.Height != dve.VoteB.Height ||
|
||||||
dve.VoteA.Round != dve.VoteB.Round ||
|
dve.VoteA.Round != dve.VoteB.Round ||
|
||||||
@ -92,7 +86,8 @@ func (dve *DuplicateVoteEvidence) Verify(chainID string) error {
|
|||||||
if !bytes.Equal(dve.VoteA.ValidatorAddress, dve.VoteB.ValidatorAddress) {
|
if !bytes.Equal(dve.VoteA.ValidatorAddress, dve.VoteB.ValidatorAddress) {
|
||||||
return fmt.Errorf("DuplicateVoteEvidence Error: Validator addresses do not match. Got %X and %X", dve.VoteA.ValidatorAddress, dve.VoteB.ValidatorAddress)
|
return fmt.Errorf("DuplicateVoteEvidence Error: Validator addresses do not match. Got %X and %X", dve.VoteA.ValidatorAddress, dve.VoteB.ValidatorAddress)
|
||||||
}
|
}
|
||||||
// XXX: Should we enforce index is the same ?
|
|
||||||
|
// Index must be the same
|
||||||
if dve.VoteA.ValidatorIndex != dve.VoteB.ValidatorIndex {
|
if dve.VoteA.ValidatorIndex != dve.VoteB.ValidatorIndex {
|
||||||
return fmt.Errorf("DuplicateVoteEvidence Error: Validator indices do not match. Got %d and %d", dve.VoteA.ValidatorIndex, dve.VoteB.ValidatorIndex)
|
return fmt.Errorf("DuplicateVoteEvidence Error: Validator indices do not match. Got %d and %d", dve.VoteA.ValidatorIndex, dve.VoteB.ValidatorIndex)
|
||||||
}
|
}
|
||||||
@ -102,11 +97,18 @@ func (dve *DuplicateVoteEvidence) Verify(chainID string) error {
|
|||||||
return fmt.Errorf("DuplicateVoteEvidence Error: BlockIDs are the same (%v) - not a real duplicate vote", dve.VoteA.BlockID)
|
return fmt.Errorf("DuplicateVoteEvidence Error: BlockIDs are the same (%v) - not a real duplicate vote", dve.VoteA.BlockID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pubkey must match address (this should already be true, sanity check)
|
||||||
|
addr := dve.VoteA.ValidatorAddress
|
||||||
|
if !bytes.Equal(pubKey.Address(), addr) {
|
||||||
|
return fmt.Errorf("DuplicateVoteEvidence FAILED SANITY CHECK - address (%X) doesn't match pubkey (%v - %X)",
|
||||||
|
addr, pubKey, pubKey.Address())
|
||||||
|
}
|
||||||
|
|
||||||
// Signatures must be valid
|
// Signatures must be valid
|
||||||
if !dve.PubKey.VerifyBytes(dve.VoteA.SignBytes(chainID), dve.VoteA.Signature) {
|
if !pubKey.VerifyBytes(dve.VoteA.SignBytes(chainID), dve.VoteA.Signature) {
|
||||||
return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteA: %v", ErrVoteInvalidSignature)
|
return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteA: %v", ErrVoteInvalidSignature)
|
||||||
}
|
}
|
||||||
if !dve.PubKey.VerifyBytes(dve.VoteB.SignBytes(chainID), dve.VoteB.Signature) {
|
if !pubKey.VerifyBytes(dve.VoteB.SignBytes(chainID), dve.VoteB.Signature) {
|
||||||
return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteB: %v", ErrVoteInvalidSignature)
|
return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteB: %v", ErrVoteInvalidSignature)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,29 +133,26 @@ func (dve *DuplicateVoteEvidence) Equal(ev Evidence) bool {
|
|||||||
type MockGoodEvidence struct {
|
type MockGoodEvidence struct {
|
||||||
Height_ int64
|
Height_ int64
|
||||||
Address_ []byte
|
Address_ []byte
|
||||||
Index_ int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UNSTABLE
|
// UNSTABLE
|
||||||
func NewMockGoodEvidence(height int64, index int, address []byte) MockGoodEvidence {
|
func NewMockGoodEvidence(height int64, idx int, address []byte) MockGoodEvidence {
|
||||||
return MockGoodEvidence{height, address, index}
|
return MockGoodEvidence{height, address}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e MockGoodEvidence) Height() int64 { return e.Height_ }
|
func (e MockGoodEvidence) Height() int64 { return e.Height_ }
|
||||||
func (e MockGoodEvidence) Address() []byte { return e.Address_ }
|
func (e MockGoodEvidence) Address() []byte { return e.Address_ }
|
||||||
func (e MockGoodEvidence) Index() int { return e.Index_ }
|
|
||||||
func (e MockGoodEvidence) Hash() []byte {
|
func (e MockGoodEvidence) Hash() []byte {
|
||||||
return []byte(fmt.Sprintf("%d-%d", e.Height_, e.Index_))
|
return []byte(fmt.Sprintf("%d-%x", e.Height_, e.Address_))
|
||||||
}
|
}
|
||||||
func (e MockGoodEvidence) Verify(chainID string) error { return nil }
|
func (e MockGoodEvidence) Verify(chainID string, pubKey crypto.PubKey) error { return nil }
|
||||||
func (e MockGoodEvidence) Equal(ev Evidence) bool {
|
func (e MockGoodEvidence) Equal(ev Evidence) bool {
|
||||||
e2 := ev.(MockGoodEvidence)
|
e2 := ev.(MockGoodEvidence)
|
||||||
return e.Height_ == e2.Height_ &&
|
return e.Height_ == e2.Height_ &&
|
||||||
bytes.Equal(e.Address_, e2.Address_) &&
|
bytes.Equal(e.Address_, e2.Address_)
|
||||||
e.Index_ == e2.Index_
|
|
||||||
}
|
}
|
||||||
func (e MockGoodEvidence) String() string {
|
func (e MockGoodEvidence) String() string {
|
||||||
return fmt.Sprintf("GoodEvidence: %d/%s/%d", e.Height_, e.Address_, e.Index_)
|
return fmt.Sprintf("GoodEvidence: %d/%s", e.Height_, e.Address_)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UNSTABLE
|
// UNSTABLE
|
||||||
@ -161,15 +160,16 @@ type MockBadEvidence struct {
|
|||||||
MockGoodEvidence
|
MockGoodEvidence
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e MockBadEvidence) Verify(chainID string) error { return fmt.Errorf("MockBadEvidence") }
|
func (e MockBadEvidence) Verify(chainID string, pubKey crypto.PubKey) error {
|
||||||
|
return fmt.Errorf("MockBadEvidence")
|
||||||
|
}
|
||||||
func (e MockBadEvidence) Equal(ev Evidence) bool {
|
func (e MockBadEvidence) Equal(ev Evidence) bool {
|
||||||
e2 := ev.(MockBadEvidence)
|
e2 := ev.(MockBadEvidence)
|
||||||
return e.Height_ == e2.Height_ &&
|
return e.Height_ == e2.Height_ &&
|
||||||
bytes.Equal(e.Address_, e2.Address_) &&
|
bytes.Equal(e.Address_, e2.Address_)
|
||||||
e.Index_ == e2.Index_
|
|
||||||
}
|
}
|
||||||
func (e MockBadEvidence) String() string {
|
func (e MockBadEvidence) String() string {
|
||||||
return fmt.Sprintf("BadEvidence: %d/%s/%d", e.Height_, e.Address_, e.Index_)
|
return fmt.Sprintf("BadEvidence: %d/%s", e.Height_, e.Address_)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------
|
//-------------------------------------------
|
||||||
|
@ -59,17 +59,16 @@ func TestEvidence(t *testing.T) {
|
|||||||
{vote1, badVote, false}, // signed by wrong key
|
{vote1, badVote, false}, // signed by wrong key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pubKey := val.GetPubKey()
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
ev := &DuplicateVoteEvidence{
|
ev := &DuplicateVoteEvidence{
|
||||||
PubKey: val.GetPubKey(),
|
|
||||||
VoteA: c.vote1,
|
VoteA: c.vote1,
|
||||||
VoteB: c.vote2,
|
VoteB: c.vote2,
|
||||||
}
|
}
|
||||||
if c.valid {
|
if c.valid {
|
||||||
assert.Nil(t, ev.Verify(chainID), "evidence should be valid")
|
assert.Nil(t, ev.Verify(chainID, pubKey), "evidence should be valid")
|
||||||
} else {
|
} else {
|
||||||
assert.NotNil(t, ev.Verify(chainID), "evidence should be invalid")
|
assert.NotNil(t, ev.Verify(chainID, pubKey), "evidence should be invalid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,71 +1,167 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/tendermint/abci/types"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/abci/types"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TM2PB is used for converting Tendermint types to protobuf types.
|
//-------------------------------------------------------
|
||||||
|
// Use strings to distinguish types in ABCI messages
|
||||||
|
|
||||||
|
const (
|
||||||
|
ABCIEvidenceTypeDuplicateVote = "duplicate/vote"
|
||||||
|
ABCIEvidenceTypeMockGood = "mock/good"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ABCIPubKeyTypeEd25519 = "ed25519"
|
||||||
|
ABCIPubKeyTypeSecp256k1 = "secp256k1"
|
||||||
|
)
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
// TM2PB is used for converting Tendermint ABCI to protobuf ABCI.
|
||||||
// UNSTABLE
|
// UNSTABLE
|
||||||
var TM2PB = tm2pb{}
|
var TM2PB = tm2pb{}
|
||||||
|
|
||||||
type tm2pb struct{}
|
type tm2pb struct{}
|
||||||
|
|
||||||
func (tm2pb) Header(header *Header) types.Header {
|
func (tm2pb) Header(header *Header) abci.Header {
|
||||||
return types.Header{
|
return abci.Header{
|
||||||
ChainID: header.ChainID,
|
ChainID: header.ChainID,
|
||||||
Height: header.Height,
|
Height: header.Height,
|
||||||
Time: header.Time.Unix(),
|
Time: header.Time.Unix(),
|
||||||
NumTxs: int32(header.NumTxs), // XXX: overflow
|
NumTxs: int32(header.NumTxs), // XXX: overflow
|
||||||
LastBlockID: TM2PB.BlockID(header.LastBlockID),
|
LastBlockHash: header.LastBlockID.Hash,
|
||||||
LastCommitHash: header.LastCommitHash,
|
ValidatorsHash: header.ValidatorsHash,
|
||||||
DataHash: header.DataHash,
|
|
||||||
AppHash: header.AppHash,
|
AppHash: header.AppHash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm2pb) BlockID(blockID BlockID) types.BlockID {
|
func (tm2pb) Validator(val *Validator) abci.Validator {
|
||||||
return types.BlockID{
|
return abci.Validator{
|
||||||
Hash: blockID.Hash,
|
PubKey: TM2PB.PubKey(val.PubKey),
|
||||||
Parts: TM2PB.PartSetHeader(blockID.PartsHeader),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm2pb) PartSetHeader(partSetHeader PartSetHeader) types.PartSetHeader {
|
|
||||||
return types.PartSetHeader{
|
|
||||||
Total: int32(partSetHeader.Total), // XXX: overflow
|
|
||||||
Hash: partSetHeader.Hash,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm2pb) Validator(val *Validator) types.Validator {
|
|
||||||
return types.Validator{
|
|
||||||
PubKey: val.PubKey.Bytes(),
|
|
||||||
Power: val.VotingPower,
|
Power: val.VotingPower,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm2pb) Validators(vals *ValidatorSet) []types.Validator {
|
func (tm2pb) PubKey(pubKey crypto.PubKey) abci.PubKey {
|
||||||
validators := make([]types.Validator, len(vals.Validators))
|
switch pk := pubKey.(type) {
|
||||||
|
case crypto.PubKeyEd25519:
|
||||||
|
return abci.PubKey{
|
||||||
|
Type: ABCIPubKeyTypeEd25519,
|
||||||
|
Data: pk[:],
|
||||||
|
}
|
||||||
|
case crypto.PubKeySecp256k1:
|
||||||
|
return abci.PubKey{
|
||||||
|
Type: ABCIPubKeyTypeSecp256k1,
|
||||||
|
Data: pk[:],
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unknown pubkey type: %v %v", pubKey, reflect.TypeOf(pubKey)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tm2pb) Validators(vals *ValidatorSet) []abci.Validator {
|
||||||
|
validators := make([]abci.Validator, len(vals.Validators))
|
||||||
for i, val := range vals.Validators {
|
for i, val := range vals.Validators {
|
||||||
validators[i] = TM2PB.Validator(val)
|
validators[i] = TM2PB.Validator(val)
|
||||||
}
|
}
|
||||||
return validators
|
return validators
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm2pb) ConsensusParams(params *ConsensusParams) *types.ConsensusParams {
|
func (tm2pb) ConsensusParams(params *ConsensusParams) *abci.ConsensusParams {
|
||||||
return &types.ConsensusParams{
|
return &abci.ConsensusParams{
|
||||||
BlockSize: &types.BlockSize{
|
BlockSize: &abci.BlockSize{
|
||||||
|
|
||||||
MaxBytes: int32(params.BlockSize.MaxBytes),
|
MaxBytes: int32(params.BlockSize.MaxBytes),
|
||||||
MaxTxs: int32(params.BlockSize.MaxTxs),
|
MaxTxs: int32(params.BlockSize.MaxTxs),
|
||||||
MaxGas: params.BlockSize.MaxGas,
|
MaxGas: params.BlockSize.MaxGas,
|
||||||
},
|
},
|
||||||
TxSize: &types.TxSize{
|
TxSize: &abci.TxSize{
|
||||||
MaxBytes: int32(params.TxSize.MaxBytes),
|
MaxBytes: int32(params.TxSize.MaxBytes),
|
||||||
MaxGas: params.TxSize.MaxGas,
|
MaxGas: params.TxSize.MaxGas,
|
||||||
},
|
},
|
||||||
BlockGossip: &types.BlockGossip{
|
BlockGossip: &abci.BlockGossip{
|
||||||
BlockPartSizeBytes: int32(params.BlockGossip.BlockPartSizeBytes),
|
BlockPartSizeBytes: int32(params.BlockGossip.BlockPartSizeBytes),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ABCI Evidence includes information from the past that's not included in the evidence itself
|
||||||
|
// so Evidence types stays compact.
|
||||||
|
func (tm2pb) Evidence(ev Evidence, valSet *ValidatorSet, evTime time.Time) abci.Evidence {
|
||||||
|
_, val := valSet.GetByAddress(ev.Address())
|
||||||
|
if val == nil {
|
||||||
|
// should already have checked this
|
||||||
|
panic(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
abciEvidence := abci.Evidence{
|
||||||
|
Validator: abci.Validator{
|
||||||
|
Address: ev.Address(),
|
||||||
|
PubKey: TM2PB.PubKey(val.PubKey),
|
||||||
|
Power: val.VotingPower,
|
||||||
|
},
|
||||||
|
Height: ev.Height(),
|
||||||
|
Time: evTime.Unix(),
|
||||||
|
TotalVotingPower: valSet.TotalVotingPower(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// set type
|
||||||
|
switch ev.(type) {
|
||||||
|
case *DuplicateVoteEvidence:
|
||||||
|
abciEvidence.Type = ABCIEvidenceTypeDuplicateVote
|
||||||
|
case *MockGoodEvidence, MockGoodEvidence:
|
||||||
|
abciEvidence.Type = ABCIEvidenceTypeMockGood
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("Unknown evidence type: %v %v", ev, reflect.TypeOf(ev)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return abciEvidence
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tm2pb) ValidatorFromPubKeyAndPower(pubkey crypto.PubKey, power int64) abci.Validator {
|
||||||
|
pubkeyABCI := TM2PB.PubKey(pubkey)
|
||||||
|
return abci.Validator{
|
||||||
|
Address: pubkey.Address(),
|
||||||
|
PubKey: pubkeyABCI,
|
||||||
|
Power: power,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// PB2TM is used for converting protobuf ABCI to Tendermint ABCI.
|
||||||
|
// UNSTABLE
|
||||||
|
var PB2TM = pb2tm{}
|
||||||
|
|
||||||
|
type pb2tm struct{}
|
||||||
|
|
||||||
|
func (pb2tm) PubKey(pubKey abci.PubKey) (crypto.PubKey, error) {
|
||||||
|
// TODO: define these in go-crypto and use them
|
||||||
|
sizeEd := 32
|
||||||
|
sizeSecp := 33
|
||||||
|
switch pubKey.Type {
|
||||||
|
case ABCIPubKeyTypeEd25519:
|
||||||
|
if len(pubKey.Data) != sizeEd {
|
||||||
|
return nil, fmt.Errorf("Invalid size for PubKeyEd25519. Got %d, expected %d", len(pubKey.Data), sizeEd)
|
||||||
|
}
|
||||||
|
var pk crypto.PubKeyEd25519
|
||||||
|
copy(pk[:], pubKey.Data)
|
||||||
|
return pk, nil
|
||||||
|
case ABCIPubKeyTypeSecp256k1:
|
||||||
|
if len(pubKey.Data) != sizeSecp {
|
||||||
|
return nil, fmt.Errorf("Invalid size for PubKeyEd25519. Got %d, expected %d", len(pubKey.Data), sizeSecp)
|
||||||
|
}
|
||||||
|
var pk crypto.PubKeySecp256k1
|
||||||
|
copy(pk[:], pubKey.Data)
|
||||||
|
return pk, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Unknown pubkey type %v", pubKey.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user