diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ccc7e0a7..e911e0734 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,14 +31,16 @@ BUG FIXES: ## 0.11.0 (September 22, 2017) BREAKING: - - state: every validator set change is persisted to disk, which required some changes to the `State` structure. - - cmd: if there is no genesis, exit immediately instead of waiting around for one to show. - - p2p: new `p2p.Peer` interface used for all reactor methods (instead of `*p2p.Peer` struct). - - types: `Signer.Sign` returns an error. + - genesis file: validator `amount` is now `power` + - abci: Info, BeginBlock, InitChain all take structs - rpc: various changes to match JSONRPC spec (http://www.jsonrpc.org/specification), including breaking ones: - requests that previously returned HTTP code 4XX now return 200 with an error code in the JSONRPC. - `rpctypes.RPCResponse` uses new `RPCError` type instead of `string`. - - abci: Info, BeginBlock, InitChain all take structs + + - cmd: if there is no genesis, exit immediately instead of waiting around for one to show. + - types: `Signer.Sign` returns an error. + - state: every validator set change is persisted to disk, which required some changes to the `State` structure. + - p2p: new `p2p.Peer` interface used for all reactor methods (instead of `*p2p.Peer` struct). FEATURES: - rpc: `/validators?height=X` allows querying of validators at previous heights. diff --git a/benchmarks/map_test.go b/benchmarks/map_test.go index 80edaff7c..2d9789026 100644 --- a/benchmarks/map_test.go +++ b/benchmarks/map_test.go @@ -1,8 +1,9 @@ package benchmarks import ( - . "github.com/tendermint/tmlibs/common" "testing" + + cmn "github.com/tendermint/tmlibs/common" ) func BenchmarkSomething(b *testing.B) { @@ -11,11 +12,11 @@ func BenchmarkSomething(b *testing.B) { numChecks := 100000 keys := make([]string, numItems) for i := 0; i < numItems; i++ { - keys[i] = RandStr(100) + keys[i] = cmn.RandStr(100) } txs := make([]string, numChecks) for i := 0; i < numChecks; i++ { - txs[i] = RandStr(100) + txs[i] = cmn.RandStr(100) } b.StartTimer() diff --git a/benchmarks/os_test.go b/benchmarks/os_test.go index 2c4611c84..9c8fae656 100644 --- a/benchmarks/os_test.go +++ b/benchmarks/os_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" ) func BenchmarkFileWrite(b *testing.B) { @@ -14,7 +14,7 @@ func BenchmarkFileWrite(b *testing.B) { if err != nil { b.Error(err) } - testString := RandStr(200) + "\n" + testString := cmn.RandStr(200) + "\n" b.StartTimer() for i := 0; i < b.N; i++ { diff --git a/benchmarks/simu/counter.go b/benchmarks/simu/counter.go index d26f5e6f7..ff5b14c0d 100644 --- a/benchmarks/simu/counter.go +++ b/benchmarks/simu/counter.go @@ -3,9 +3,8 @@ package main import ( "context" "encoding/binary" - "time" - //"encoding/hex" "fmt" + "time" rpcclient "github.com/tendermint/tendermint/rpc/lib/client" cmn "github.com/tendermint/tmlibs/common" diff --git a/blockchain/pool.go b/blockchain/pool.go index 924880c08..bd52e280f 100644 --- a/blockchain/pool.go +++ b/blockchain/pool.go @@ -6,7 +6,7 @@ import ( "time" "github.com/tendermint/tendermint/types" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" flow "github.com/tendermint/tmlibs/flowrate" "github.com/tendermint/tmlibs/log" ) @@ -33,7 +33,7 @@ var peerTimeoutSeconds = time.Duration(15) // not const so we can override with */ type BlockPool struct { - BaseService + cmn.BaseService startTime time.Time mtx sync.Mutex @@ -59,7 +59,7 @@ func NewBlockPool(start int, requestsCh chan<- BlockRequest, timeoutsCh chan<- s requestsCh: requestsCh, timeoutsCh: timeoutsCh, } - bp.BaseService = *NewBaseService(nil, "BlockPool", bp) + bp.BaseService = *cmn.NewBaseService(nil, "BlockPool", bp) return bp } @@ -137,14 +137,14 @@ func (pool *BlockPool) IsCaughtUp() bool { maxPeerHeight := 0 for _, peer := range pool.peers { - maxPeerHeight = MaxInt(maxPeerHeight, peer.height) + maxPeerHeight = cmn.MaxInt(maxPeerHeight, peer.height) } // some conditions to determine if we're caught up receivedBlockOrTimedOut := (pool.height > 0 || time.Since(pool.startTime) > 5*time.Second) ourChainIsLongestAmongPeers := maxPeerHeight == 0 || pool.height >= maxPeerHeight isCaughtUp := receivedBlockOrTimedOut && ourChainIsLongestAmongPeers - pool.Logger.Info(Fmt("IsCaughtUp: %v", isCaughtUp), "height", pool.height, "maxPeerHeight", maxPeerHeight) + pool.Logger.Info(cmn.Fmt("IsCaughtUp: %v", isCaughtUp), "height", pool.height, "maxPeerHeight", maxPeerHeight) return isCaughtUp } @@ -180,7 +180,7 @@ func (pool *BlockPool) PopRequest() { delete(pool.requesters, pool.height) pool.height++ } else { - PanicSanity(Fmt("Expected requester to pop, got nothing at height %v", pool.height)) + cmn.PanicSanity(cmn.Fmt("Expected requester to pop, got nothing at height %v", pool.height)) } } @@ -192,7 +192,7 @@ func (pool *BlockPool) RedoRequest(height int) { pool.mtx.Unlock() if request.block == nil { - PanicSanity("Expected block to be non-nil") + cmn.PanicSanity("Expected block to be non-nil") } // RemovePeer will redo all requesters associated with this peer. // TODO: record this malfeasance @@ -311,10 +311,10 @@ func (pool *BlockPool) debug() string { str := "" for h := pool.height; h < pool.height+len(pool.requesters); h++ { if pool.requesters[h] == nil { - str += Fmt("H(%v):X ", h) + str += cmn.Fmt("H(%v):X ", h) } else { - str += Fmt("H(%v):", h) - str += Fmt("B?(%v) ", pool.requesters[h].block != nil) + str += cmn.Fmt("H(%v):", h) + str += cmn.Fmt("B?(%v) ", pool.requesters[h].block != nil) } } return str @@ -394,7 +394,7 @@ func (peer *bpPeer) onTimeout() { //------------------------------------- type bpRequester struct { - BaseService + cmn.BaseService pool *BlockPool height int gotBlockCh chan struct{} @@ -415,7 +415,7 @@ func newBPRequester(pool *BlockPool, height int) *bpRequester { peerID: "", block: nil, } - bpr.BaseService = *NewBaseService(nil, "bpRequester", bpr) + bpr.BaseService = *cmn.NewBaseService(nil, "bpRequester", bpr) return bpr } diff --git a/blockchain/pool_test.go b/blockchain/pool_test.go index 43ddbaddf..a1fce2da8 100644 --- a/blockchain/pool_test.go +++ b/blockchain/pool_test.go @@ -6,7 +6,7 @@ import ( "time" "github.com/tendermint/tendermint/types" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" "github.com/tendermint/tmlibs/log" ) @@ -22,7 +22,7 @@ type testPeer struct { func makePeers(numPeers int, minHeight, maxHeight int) map[string]testPeer { peers := make(map[string]testPeer, numPeers) for i := 0; i < numPeers; i++ { - peerID := RandStr(12) + peerID := cmn.RandStr(12) height := minHeight + rand.Intn(maxHeight-minHeight) peers[peerID] = testPeer{peerID, height} } diff --git a/blockchain/reactor.go b/blockchain/reactor.go index fb68aadda..7ebf31796 100644 --- a/blockchain/reactor.go +++ b/blockchain/reactor.go @@ -235,7 +235,7 @@ FOR_LOOP: err := bcR.state.Validators.VerifyCommit( bcR.state.ChainID, types.BlockID{first.Hash(), firstPartsHeader}, first.Height, second.LastCommit) if err != nil { - bcR.Logger.Info("error in validation", "err", err) + bcR.Logger.Error("Error in validation", "err", err) bcR.pool.RedoRequest(first.Height) break SYNC_LOOP } else { diff --git a/cmd/tendermint/commands/root_test.go b/cmd/tendermint/commands/root_test.go index ae0f38275..b89e7a199 100644 --- a/cmd/tendermint/commands/root_test.go +++ b/cmd/tendermint/commands/root_test.go @@ -3,15 +3,15 @@ package commands import ( "os" "strconv" + "testing" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tmlibs/cli" - - "testing" ) var ( diff --git a/consensus/byzantine_test.go b/consensus/byzantine_test.go index 0f2d7b040..38dff4064 100644 --- a/consensus/byzantine_test.go +++ b/consensus/byzantine_test.go @@ -9,7 +9,7 @@ import ( data "github.com/tendermint/go-wire/data" "github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/types" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" "github.com/tendermint/tmlibs/events" ) @@ -149,8 +149,8 @@ func TestByzantine(t *testing.T) { case <-done: case <-tick.C: for i, reactor := range reactors { - t.Log(Fmt("Consensus Reactor %v", i)) - t.Log(Fmt("%v", reactor)) + t.Log(cmn.Fmt("Consensus Reactor %v", i)) + t.Log(cmn.Fmt("%v", reactor)) } t.Fatalf("Timed out waiting for all validators to commit first block") } @@ -220,7 +220,7 @@ func sendProposalAndParts(height, round int, cs *ConsensusState, peer p2p.Peer, // byzantine consensus reactor type ByzantineReactor struct { - Service + cmn.Service reactor *ConsensusReactor } @@ -296,5 +296,5 @@ func (privVal *ByzantinePrivValidator) SignHeartbeat(chainID string, heartbeat * } func (privVal *ByzantinePrivValidator) String() string { - return Fmt("PrivValidator{%X}", privVal.GetAddress()) + return cmn.Fmt("PrivValidator{%X}", privVal.GetAddress()) } diff --git a/consensus/common_test.go b/consensus/common_test.go index b16afc3d0..e614bf371 100644 --- a/consensus/common_test.go +++ b/consensus/common_test.go @@ -19,7 +19,7 @@ import ( "github.com/tendermint/tendermint/p2p" sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/types" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -34,7 +34,7 @@ var config *cfg.Config // NOTE: must be reset for each _test.go file var ensureTimeout = time.Second * 2 func ensureDir(dir string, mode os.FileMode) { - if err := EnsureDir(dir, mode); err != nil { + if err := cmn.EnsureDir(dir, mode); err != nil { panic(err) } } @@ -341,7 +341,7 @@ func randConsensusNet(nValidators int, testName string, tickerFunc func() Timeou state, _ := sm.MakeGenesisState(db, genDoc) state.SetLogger(logger.With("module", "state", "validator", i)) state.Save() - thisConfig := ResetConfig(Fmt("%s_%d", testName, i)) + thisConfig := ResetConfig(cmn.Fmt("%s_%d", testName, i)) for _, opt := range configOpts { opt(thisConfig) } @@ -362,13 +362,13 @@ func randConsensusNetWithPeers(nValidators, nPeers int, testName string, tickerF state, _ := sm.MakeGenesisState(db, genDoc) state.SetLogger(log.TestingLogger().With("module", "state")) state.Save() - thisConfig := ResetConfig(Fmt("%s_%d", testName, i)) + thisConfig := ResetConfig(cmn.Fmt("%s_%d", testName, i)) ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal var privVal types.PrivValidator if i < nValidators { privVal = privVals[i] } else { - _, tempFilePath := Tempfile("priv_validator_") + _, tempFilePath := cmn.Tempfile("priv_validator_") privVal = types.GenPrivValidatorFS(tempFilePath) } diff --git a/consensus/height_vote_set.go b/consensus/height_vote_set.go index 455004f92..019b2642b 100644 --- a/consensus/height_vote_set.go +++ b/consensus/height_vote_set.go @@ -5,7 +5,7 @@ import ( "sync" "github.com/tendermint/tendermint/types" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" ) type RoundVoteSet struct { @@ -76,7 +76,7 @@ func (hvs *HeightVoteSet) SetRound(round int) { hvs.mtx.Lock() defer hvs.mtx.Unlock() if hvs.round != 0 && (round < hvs.round+1) { - PanicSanity("SetRound() must increment hvs.round") + cmn.PanicSanity("SetRound() must increment hvs.round") } for r := hvs.round + 1; r <= round; r++ { if _, ok := hvs.roundVoteSets[r]; ok { @@ -89,7 +89,7 @@ func (hvs *HeightVoteSet) SetRound(round int) { func (hvs *HeightVoteSet) addRound(round int) { if _, ok := hvs.roundVoteSets[round]; ok { - PanicSanity("addRound() for an existing round") + cmn.PanicSanity("addRound() for an existing round") } // log.Debug("addRound(round)", "round", round) prevotes := types.NewVoteSet(hvs.chainID, hvs.height, round, types.VoteTypePrevote, hvs.valSet) @@ -164,7 +164,7 @@ func (hvs *HeightVoteSet) getVoteSet(round int, type_ byte) *types.VoteSet { case types.VoteTypePrecommit: return rvs.Precommits default: - PanicSanity(Fmt("Unexpected vote type %X", type_)) + cmn.PanicSanity(cmn.Fmt("Unexpected vote type %X", type_)) return nil } } @@ -194,7 +194,7 @@ func (hvs *HeightVoteSet) StringIndented(indent string) string { voteSetString = roundVoteSet.Precommits.StringShort() vsStrings = append(vsStrings, voteSetString) } - return Fmt(`HeightVoteSet{H:%v R:0~%v + return cmn.Fmt(`HeightVoteSet{H:%v R:0~%v %s %v %s}`, hvs.height, hvs.round, diff --git a/consensus/height_vote_set_test.go b/consensus/height_vote_set_test.go index 7e03e40f5..30eab5ae9 100644 --- a/consensus/height_vote_set_test.go +++ b/consensus/height_vote_set_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/tendermint/tendermint/types" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" ) func init() { @@ -57,7 +57,7 @@ func makeVoteHR(t *testing.T, height, round int, privVals []*types.PrivValidator chainID := config.ChainID err := privVal.SignVote(chainID, vote) if err != nil { - panic(Fmt("Error signing vote: %v", err)) + panic(cmn.Fmt("Error signing vote: %v", err)) return nil } return vote diff --git a/consensus/mempool_test.go b/consensus/mempool_test.go index f17d19f52..3a430ef26 100644 --- a/consensus/mempool_test.go +++ b/consensus/mempool_test.go @@ -8,7 +8,7 @@ import ( abci "github.com/tendermint/abci/types" "github.com/tendermint/tendermint/types" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" ) func init() { @@ -86,7 +86,7 @@ func deliverTxsRange(cs *ConsensusState, start, end int) { binary.BigEndian.PutUint64(txBytes, uint64(i)) err := cs.mempool.CheckTx(txBytes, nil) if err != nil { - panic(Fmt("Error after CheckTx: %v", err)) + panic(cmn.Fmt("Error after CheckTx: %v", err)) } } } @@ -184,7 +184,7 @@ func NewCounterApplication() *CounterApplication { } func (app *CounterApplication) Info(req abci.RequestInfo) abci.ResponseInfo { - return abci.ResponseInfo{Data: Fmt("txs:%v", app.txCount)} + return abci.ResponseInfo{Data: cmn.Fmt("txs:%v", app.txCount)} } func (app *CounterApplication) DeliverTx(tx []byte) abci.Result { @@ -201,7 +201,7 @@ func runTx(tx []byte, countPtr *int) abci.Result { copy(tx8[len(tx8)-len(tx):], tx) txValue := binary.BigEndian.Uint64(tx8) if txValue != uint64(count) { - return abci.ErrBadNonce.AppendLog(Fmt("Invalid nonce. Expected %v, got %v", count, txValue)) + return abci.ErrBadNonce.AppendLog(cmn.Fmt("Invalid nonce. Expected %v, got %v", count, txValue)) } *countPtr += 1 return abci.OK diff --git a/consensus/state.go b/consensus/state.go index 648fc0559..bed40eb1d 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -6,6 +6,7 @@ import ( "fmt" "path/filepath" "reflect" + "runtime/debug" "sync" "time" @@ -609,7 +610,7 @@ func (cs *ConsensusState) newStep() { func (cs *ConsensusState) receiveRoutine(maxSteps int) { defer func() { if r := recover(); r != nil { - cs.Logger.Error("CONSENSUS FAILURE!!!", "err", r) + cs.Logger.Error("CONSENSUS FAILURE!!!", "err", r, "stack", string(debug.Stack())) } }() diff --git a/consensus/state_test.go b/consensus/state_test.go index c4a6769e9..246fd879d 100644 --- a/consensus/state_test.go +++ b/consensus/state_test.go @@ -7,7 +7,7 @@ import ( "time" "github.com/tendermint/tendermint/types" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" ) func init() { @@ -80,7 +80,7 @@ func TestProposerSelection0(t *testing.T) { prop = cs1.GetRoundState().Validators.GetProposer() if !bytes.Equal(prop.Address, vss[1].GetAddress()) { - panic(Fmt("expected proposer to be validator %d. Got %X", 1, prop.Address)) + panic(cmn.Fmt("expected proposer to be validator %d. Got %X", 1, prop.Address)) } } @@ -101,7 +101,7 @@ func TestProposerSelection2(t *testing.T) { for i := 0; i < len(vss); i++ { prop := cs1.GetRoundState().Validators.GetProposer() if !bytes.Equal(prop.Address, vss[(i+2)%len(vss)].GetAddress()) { - panic(Fmt("expected proposer to be validator %d. Got %X", (i+2)%len(vss), prop.Address)) + panic(cmn.Fmt("expected proposer to be validator %d. Got %X", (i+2)%len(vss), prop.Address)) } rs := cs1.GetRoundState() @@ -432,7 +432,7 @@ func TestLockNoPOL(t *testing.T) { // now we're on a new round and are the proposer if !bytes.Equal(rs.ProposalBlock.Hash(), rs.LockedBlock.Hash()) { - panic(Fmt("Expected proposal block to be locked block. Got %v, Expected %v", rs.ProposalBlock, rs.LockedBlock)) + panic(cmn.Fmt("Expected proposal block to be locked block. Got %v, Expected %v", rs.ProposalBlock, rs.LockedBlock)) } <-voteCh // prevote diff --git a/consensus/version.go b/consensus/version.go index 84f1ec81f..2c137bf7f 100644 --- a/consensus/version.go +++ b/consensus/version.go @@ -1,7 +1,7 @@ package consensus import ( - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" ) // kind of arbitrary @@ -10,4 +10,4 @@ var Major = "0" // var Minor = "2" // replay refactor var Revision = "2" // validation -> commit -var Version = Fmt("v%s/%s.%s.%s", Spec, Major, Minor, Revision) +var Version = cmn.Fmt("v%s/%s.%s.%s", Spec, Major, Minor, Revision) diff --git a/consensus/wal.go b/consensus/wal.go index a2ac470a0..f9a2a8015 100644 --- a/consensus/wal.go +++ b/consensus/wal.go @@ -6,7 +6,7 @@ import ( wire "github.com/tendermint/go-wire" "github.com/tendermint/tendermint/types" auto "github.com/tendermint/tmlibs/autofile" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" ) //-------------------------------------------------------- @@ -34,7 +34,7 @@ var _ = wire.RegisterInterface( // TODO: currently the wal is overwritten during replay catchup // give it a mode so it's either reading or appending - must read to end to start appending again type WAL struct { - BaseService + cmn.BaseService group *auto.Group light bool // ignore block parts @@ -49,7 +49,7 @@ func NewWAL(walFile string, light bool) (*WAL, error) { group: group, light: light, } - wal.BaseService = *NewBaseService(nil, "WAL", wal) + wal.BaseService = *cmn.NewBaseService(nil, "WAL", wal) return wal, nil } @@ -86,19 +86,19 @@ func (wal *WAL) Save(wmsg WALMessage) { var wmsgBytes = wire.JSONBytes(TimedWALMessage{time.Now(), wmsg}) err := wal.group.WriteLine(string(wmsgBytes)) if err != nil { - PanicQ(Fmt("Error writing msg to consensus wal. Error: %v \n\nMessage: %v", err, wmsg)) + cmn.PanicQ(cmn.Fmt("Error writing msg to consensus wal. Error: %v \n\nMessage: %v", err, wmsg)) } // TODO: only flush when necessary if err := wal.group.Flush(); err != nil { - PanicQ(Fmt("Error flushing consensus wal buf to file. Error: %v \n", err)) + cmn.PanicQ(cmn.Fmt("Error flushing consensus wal buf to file. Error: %v \n", err)) } } func (wal *WAL) writeEndHeight(height int) { - wal.group.WriteLine(Fmt("#ENDHEIGHT: %v", height)) + wal.group.WriteLine(cmn.Fmt("#ENDHEIGHT: %v", height)) // TODO: only flush when necessary if err := wal.group.Flush(); err != nil { - PanicQ(Fmt("Error flushing consensus wal buf to file. Error: %v \n", err)) + cmn.PanicQ(cmn.Fmt("Error flushing consensus wal buf to file. Error: %v \n", err)) } } diff --git a/docs/app-development.rst b/docs/app-development.rst index 011fb0f39..770572e13 100644 --- a/docs/app-development.rst +++ b/docs/app-development.rst @@ -142,6 +142,13 @@ It is unlikely that you will need to implement a client. For details of our client, see `here `__. +Most of the examples below are from `dummy application +`__, +which is a part of the abci repo. `persistent_dummy application +`__ +is used to show ``BeginBlock``, ``EndBlock`` and ``InitChain`` +example implementations. + Blockchain Protocol ------------------- @@ -187,6 +194,12 @@ through all transactions in the mempool, removing any that were included in the block, and re-run the rest using CheckTx against the post-Commit mempool state. +:: + + func (app *DummyApplication) CheckTx(tx []byte) types.Result { + return types.OK + } + Consensus Connection ~~~~~~~~~~~~~~~~~~~~ @@ -215,6 +228,19 @@ The block header will be updated (TODO) to include some commitment to the results of DeliverTx, be it a bitarray of non-OK transactions, or a merkle root of the data returned by the DeliverTx requests, or both. +:: + + // tx is either "key=value" or just arbitrary bytes + func (app *DummyApplication) DeliverTx(tx []byte) types.Result { + parts := strings.Split(string(tx), "=") + if len(parts) == 2 { + app.state.Set([]byte(parts[0]), []byte(parts[1])) + } else { + app.state.Set(tx, tx) + } + return types.OK + } + Commit ^^^^^^ @@ -228,7 +254,7 @@ Commit, or there will be deadlock. Note also that all remaining transactions in the mempool are replayed on the mempool connection (CheckTx) following a commit. -The Commit response includes a byte array, which is the deterministic +The app should respond to the Commit request with a byte array, which is the deterministic state root of the application. It is included in the header of the next block. It can be used to provide easily verified Merkle-proofs of the state of the application. @@ -237,6 +263,13 @@ It is expected that the app will persist state to disk on Commit. The option to have all transactions replayed from some previous block is the job of the `Handshake <#handshake>`__. +:: + + func (app *DummyApplication) Commit() types.Result { + hash := app.state.Hash() + return types.NewResultOK(hash, "") + } + BeginBlock ^^^^^^^^^^ @@ -248,6 +281,17 @@ The app should remember the latest height and header (ie. from which it has run a successful Commit) so that it can tell Tendermint where to pick up from when it restarts. See information on the Handshake, below. +:: + + // Track the block hash and header information + func (app *PersistentDummyApplication) BeginBlock(params types.RequestBeginBlock) { + // update latest block info + app.blockHeader = params.Header + + // reset valset changes + app.changes = make([]*types.Validator, 0) + } + EndBlock ^^^^^^^^ @@ -260,6 +304,13 @@ EndBlock response. To remove one, include it in the list with a validator set. Note validator set changes are only available in v0.8.0 and up. +:: + + // Update the validator set + func (app *PersistentDummyApplication) EndBlock(height uint64) (resEndBlock types.ResponseEndBlock) { + return types.ResponseEndBlock{Diffs: app.changes} + } + Query Connection ~~~~~~~~~~~~~~~~ @@ -281,6 +332,34 @@ cause Tendermint to not connect to the corresponding peer: Note: these query formats are subject to change! +:: + + func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { + if reqQuery.Prove { + value, proof, exists := app.state.Proof(reqQuery.Data) + resQuery.Index = -1 // TODO make Proof return index + resQuery.Key = reqQuery.Data + resQuery.Value = value + resQuery.Proof = proof + if exists { + resQuery.Log = "exists" + } else { + resQuery.Log = "does not exist" + } + return + } else { + index, value, exists := app.state.Get(reqQuery.Data) + resQuery.Index = int64(index) + resQuery.Value = value + if exists { + resQuery.Log = "exists" + } else { + resQuery.Log = "does not exist" + } + return + } + } + Handshake ~~~~~~~~~ @@ -297,3 +376,28 @@ the app are synced to the latest block height. If the app returns a LastBlockHeight of 0, Tendermint will just replay all blocks. + +:: + + func (app *DummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { + return types.ResponseInfo{Data: cmn.Fmt("{\"size\":%v}", app.state.Size())} + } + +Genesis +~~~~~~~ + +``InitChain`` will be called once upon the genesis. ``params`` includes the +initial validator set. Later on, it may be extended to take parts of the +consensus params. + +:: + + // Save the validators in the merkle tree + func (app *PersistentDummyApplication) InitChain(params types.RequestInitChain) { + for _, v := range params.Validators { + r := app.updateValidator(v) + if r.IsErr() { + app.logger.Error("Error updating validators", "r", r) + } + } + } diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 6745b482a..4a7e4b1ba 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -73,7 +73,7 @@ Tendermint before, use: :: - tendermint init + tendermint init tendermint node If you have used Tendermint, you may want to reset the data for a new @@ -107,7 +107,24 @@ like: :: - {"jsonrpc":"2.0","id":"","result":[98,{"check_tx":{},"deliver_tx":{}}],"error":""} + { + "jsonrpc": "2.0", + "id": "", + "result": { + "check_tx": { + "code": 0, + "data": "", + "log": "" + }, + "deliver_tx": { + "code": 0, + "data": "", + "log": "" + }, + "hash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF", + "height": 154 + } + } The ``98`` is a type-byte, and can be ignored (it's useful for serializing and deserializing arbitrary json). Otherwise, this result is @@ -118,14 +135,27 @@ querying the app: :: - curl -s 'localhost:46657/abci_query?data="abcd"&path=""&prove=false' + curl -s 'localhost:46657/abci_query?data="abcd"' -The ``path`` and ``prove`` arguments can be ignored for now, and in a -future release can be left out. The result should look like: +The result should look like: :: - {"jsonrpc":"2.0","id":"","result":[112,{"response":{"value":"61626364","log":"exists"}}],"error":""} + { + "jsonrpc": "2.0", + "id": "", + "result": { + "response": { + "code": 0, + "index": 0, + "key": "", + "value": "61626364", + "proof": "", + "height": 0, + "log": "exists" + } + } + } Again, the ``112`` is the type-byte. Note the ``value`` in the result (``61626364``); this is the hex-encoding of the ASCII of ``abcd``. You @@ -144,7 +174,7 @@ Now if we query for ``name``, we should get ``satoshi``, or :: - curl -s 'localhost:46657/abci_query?data="name"&path=""&prove=false' + curl -s 'localhost:46657/abci_query?data="name"' Try some other transactions and queries to make sure everything is working! @@ -204,14 +234,48 @@ the number ``1``. If instead, we try to send a ``5``, we get an error: :: > curl localhost:46657/broadcast_tx_commit?tx=0x05 - {"jsonrpc":"2.0","id":"","result":[98,{"check_tx":{},"deliver_tx":{"code":3,"log":"Invalid nonce. Expected 1, got 5"}}],"error":""} + { + "jsonrpc": "2.0", + "id": "", + "result": { + "check_tx": { + "code": 0, + "data": "", + "log": "" + }, + "deliver_tx": { + "code": 3, + "data": "", + "log": "Invalid nonce. Expected 1, got 5" + }, + "hash": "33B93DFF98749B0D6996A70F64071347060DC19C", + "height": 38 + } + } But if we send a ``1``, it works again: :: > curl localhost:46657/broadcast_tx_commit?tx=0x01 - {"jsonrpc":"2.0","id":"","result":[98,{"check_tx":{},"deliver_tx":{}}],"error":""} + { + "jsonrpc": "2.0", + "id": "", + "result": { + "check_tx": { + "code": 0, + "data": "", + "log": "" + }, + "deliver_tx": { + "code": 0, + "data": "", + "log": "" + }, + "hash": "F17854A977F6FA7EEA1BD758E296710B86F72F3D", + "height": 87 + } + } For more details on the ``broadcast_tx`` API, see `the guide on using Tendermint <./using-tendermint.html>`__. diff --git a/docs/index.rst b/docs/index.rst index ee1307bf2..0ede0e4e9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -15,8 +15,6 @@ Welcome to Tendermint! Tendermint 101 -------------- -.. maxdepth set to 2 for sexinesss -.. but use 4 to upgrade overall documentation .. toctree:: :maxdepth: 2 @@ -25,9 +23,19 @@ Tendermint 101 getting-started.rst using-tendermint.rst +Tendermint Ecosystem +-------------------- + +.. toctree:: + :maxdepth: 2 + + ecosystem.rst + Tendermint Tools ---------------- +.. the tools/ files are pulled in from the tools repo +.. see the bottom of conf.py .. toctree:: :maxdepth: 2 @@ -38,15 +46,6 @@ Tendermint Tools tools/terraform-digitalocean.rst tools/benchmarking-and-monitoring.rst - -Tendermint Ecosystem --------------------- - -.. toctree:: - :maxdepth: 2 - - ecosystem.rst - Tendermint 102 -------------- diff --git a/docs/specification/configuration.rst b/docs/specification/configuration.rst index 81d1c41d0..94801136f 100644 --- a/docs/specification/configuration.rst +++ b/docs/specification/configuration.rst @@ -30,14 +30,16 @@ The main config parameters are defined - ``consensus.max_block_size_txs``: Maximum number of block txs. *Default*: ``10000`` +- ``consensus.create_empty_blocks``: Create empty blocks w/o txs. + *Default*: ``true`` +- ``consensus.create_empty_blocks_interval``: Block creation interval, even if empty. - ``consensus.timeout_*``: Various consensus timeout parameters - **TODO** - ``consensus.wal_file``: Consensus state WAL. *Default*: - ``"$TMHOME/data/cswal"`` + ``"$TMHOME/data/cs.wal/wal"`` - ``consensus.wal_light``: Whether to use light-mode for Consensus state WAL. *Default*: ``false`` -- ``mempool.*``: Various mempool parameters **TODO** +- ``mempool.*``: Various mempool parameters - ``p2p.addr_book_file``: Peer address book. *Default*: ``"$TMHOME/addrbook.json"``. **NOT USED** diff --git a/docs/using-tendermint.rst b/docs/using-tendermint.rst index 6e870851f..cc94245cd 100644 --- a/docs/using-tendermint.rst +++ b/docs/using-tendermint.rst @@ -126,6 +126,38 @@ Notable options include the socket address of the application Some fields from the config file can be overwritten with flags. +No Empty Blocks +--------------- + +This much requested feature was implemented in version 0.10.3. While the default behaviour of ``tendermint`` is still to create blocks approximately once per second, it is possible to disable empty blocks or set a block creation interval. In the former case, blocks will be created when there are new transactions or when the AppHash changes. + +To configure tendermint to not produce empty blocks unless there are txs or the app hash changes, +run tendermint with this additional flag: + +:: + + tendermint node --consensus.create_empty_blocks=false + +or set the configuration via the ``config.toml`` file: + +:: + + [consensus] + create_empty_blocks = false + +Remember: because the default is to *create empty blocks*, avoiding empty blocks requires the config option to be set to ``false``. + +The block interval setting allows for a delay (in seconds) between the creation of each new empty block. It is set via the ``config.toml``: + +:: + + [consensus] + create_empty_blocks_interval = 5 + +With this setting, empty blocks will be produced every 5s if no block has been produced otherwise, +regardless of the value of `create_empty_blocks`. + + Broadcast API ------------- diff --git a/glide.lock b/glide.lock index 6e295a12a..a7a2bb5a4 100644 --- a/glide.lock +++ b/glide.lock @@ -1,16 +1,18 @@ -hash: e3649cac7b1b9a23c024a9d1bbebd5a147861d55da2bca77c95129b6021850b4 -updated: 2017-09-22T13:24:29.443800586-04:00 +hash: 816d84782ab66637e02bd0a3c7f652a9a31f9b88e3ae11438c5bf641cf585f19 +updated: 2017-10-02T23:32:49.162422718-04:00 imports: - name: github.com/btcsuite/btcd - version: 4803a8291c92a1d2d41041b942a9a9e37deab065 + version: b8df516b4b267acf2de46be593a9d948d1d2c420 subpackages: - btcec +- name: github.com/btcsuite/fastsha256 + version: 637e656429416087660c84436a2a035d69d54e2e - name: github.com/ebuchman/fail-test version: 95f809107225be108efcf10a3509e4ea6ceef3c4 - name: github.com/fsnotify/fsnotify version: 4da3e2cfbabc9f751898f250b49f2439785783a1 - name: github.com/go-kit/kit - version: 0d313fb5fb3a94d87d61e6434785264e87a5d740 + version: d67bb4c202e3b91377d1079b110a6c9ce23ab2f8 subpackages: - log - log/level @@ -24,25 +26,22 @@ imports: - name: github.com/go-playground/universal-translator version: 71201497bace774495daed26a3874fd339e0b538 - name: github.com/go-stack/stack - version: 817915b46b97fd7bb80e8ab6b69f01a53ac3eebf + version: 100eb0c0a9c5b306ca2fb4f165df21d80ada4b82 - name: github.com/gogo/protobuf - version: 2adc21fd136931e0388e278825291678e1d98309 + version: f7f1376d9d231a646d4e62fe1075623ced6db327 subpackages: - proto - name: github.com/golang/protobuf - version: 130e6b02ab059e7b717a096f397c5b60111cae74 + version: 18c9bb3261723cd5401db4d0c9fbc5c3b6c70fe8 subpackages: - proto - - ptypes - ptypes/any - - ptypes/duration - - ptypes/timestamp - name: github.com/golang/snappy version: 553a641470496b2327abcac10b36396bd98e45c9 - name: github.com/gorilla/websocket - version: 6f34763140ed8887aed6a044912009832b4733d7 + version: a91eba7f97777409bc2c443f5534d41dd20c5720 - name: github.com/hashicorp/hcl - version: 68e816d1c783414e79bc65b3994d9ab6b0a722ab + version: 392dba7d905ed5d04a5794ba89f558b27e2ba1ca subpackages: - hcl/ast - hcl/parser @@ -59,31 +58,33 @@ imports: - name: github.com/kr/logfmt version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0 - name: github.com/magiconair/properties - version: 8d7837e64d3c1ee4e54a880c5a920ab4316fc90a + version: 51463bfca2576e06c62a8504b5c0f06d61312647 - name: github.com/mitchellh/mapstructure - version: d0303fe809921458f417bcf828397a65db30a7e4 + version: cc8532a8e9a55ea36402aa21efdf403a60d34096 +- name: github.com/pelletier/go-buffruneio + version: c37440a7cf42ac63b919c752ca73a85067e05992 - name: github.com/pelletier/go-toml - version: 1d6b12b7cb290426e27e6b4e38b89fcda3aeef03 + version: 13d49d4606eb801b8f01ae542b4afc4c6ee3d84a - name: github.com/pkg/errors version: 645ef00459ed84a119197bfb8d8205042c6df63d - name: github.com/rcrowley/go-metrics version: 1f30fe9094a513ce4c700b9a54458bbb0c96996c - name: github.com/spf13/afero - version: ee1bd8ee15a1306d1f9201acc41ef39cd9f99a1b + version: 9be650865eab0c12963d8753212f4f9c66cdcf12 subpackages: - mem - name: github.com/spf13/cast version: acbeb36b902d72a7a4c18e8f3241075e7ab763e4 - name: github.com/spf13/cobra - version: b78744579491c1ceeaaa3b40205e56b0591b93a3 + version: 4cdb38c072b86bf795d2c81de50784d9fdd6eb77 - name: github.com/spf13/jwalterweatherman - version: 12bd96e66386c1960ab0f74ced1362f66f552f7b + version: 8f07c835e5cc1450c082fe3a439cf87b0cbb2d99 - name: github.com/spf13/pflag - version: 7aff26db30c1be810f9de5038ec5ef96ac41fd7c + version: e57e3eeb33f795204c1ca35f56c44f83227c6e66 - name: github.com/spf13/viper - version: 25b30aa063fc18e48662b86996252eabdcf2f0c7 + version: 0967fc9aceab2ce9da34061253ac10fb99bba5b2 - name: github.com/syndtr/goleveldb - version: b89cc31ef7977104127d34c1bd31ebd1a9db2199 + version: 8c81ea47d4c41a385645e133e15510fc6a2a74b4 subpackages: - leveldb - leveldb/cache @@ -122,7 +123,7 @@ imports: subpackages: - iavl - name: github.com/tendermint/tmlibs - version: 9997e3a3b46db1d2f88aa9816ed0e7915dad6ac1 + version: 096dcb90e60aa00b748b3fe49a4b95e48ebf1e13 subpackages: - autofile - cli @@ -136,7 +137,7 @@ imports: - merkle - test - name: golang.org/x/crypto - version: 7d9177d70076375b9a59c8fde23d52d9c4a7ecd5 + version: c7af5bf2638a1164f2eb5467c39c6cffbd13a02e subpackages: - curve25519 - nacl/box @@ -147,7 +148,7 @@ imports: - ripemd160 - salsa20/salsa - name: golang.org/x/net - version: 0744d001aa8470aaa53df28d32e5ceeb8af9bd70 + version: feeb485667d1fdabe727840fe00adc22431bc86e subpackages: - context - http2 @@ -157,46 +158,43 @@ imports: - lex/httplex - trace - name: golang.org/x/sys - version: 429f518978ab01db8bb6f44b66785088e7fba58b + version: e62c3de784db939836898e5c19ffd41bece347da subpackages: - unix - name: golang.org/x/text - version: 1cbadb444a806fd9430d14ad08967ed91da4fa0a + version: 470f45bf29f4147d6fbd7dfd0a02a848e49f5bf4 subpackages: - secure/bidirule - transform - unicode/bidi - unicode/norm - name: google.golang.org/genproto - version: 1e559d0a00eef8a9a43151db4665280bd8dd5886 + version: 411e09b969b1170a9f0c467558eb4c4c110d9c77 subpackages: - googleapis/rpc/status - name: google.golang.org/grpc - version: d4b75ebd4f9f8c4a2b1cdadbdbe0d7920431ccca + version: 844f573616520565fdc6fb4db242321b5456fd6d subpackages: - - balancer - codes - - connectivity - credentials - - grpclb/grpc_lb_v1/messages + - grpclb/grpc_lb_v1 - grpclog - internal - keepalive - metadata - naming - peer - - resolver - stats - status - tap - transport - name: gopkg.in/go-playground/validator.v9 - version: a021b2ec9a8a8bb970f3f15bc42617cb520e8a64 + version: 6d8c18553ea1ac493d049edd6f102f52e618f085 - name: gopkg.in/yaml.v2 - version: eb3733d160e74a9c7e442f435eb3bea458e1d19f + version: cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b testImports: - name: github.com/davecgh/go-spew - version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9 + version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 subpackages: - spew - name: github.com/pmezard/go-difflib @@ -204,7 +202,7 @@ testImports: subpackages: - difflib - name: github.com/stretchr/testify - version: 890a5c3458b43e6104ff5da8dfa139d013d77544 + version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0 subpackages: - assert - require diff --git a/glide.yaml b/glide.yaml index 58f25711d..27b6cc395 100644 --- a/glide.yaml +++ b/glide.yaml @@ -30,7 +30,7 @@ import: subpackages: - iavl - package: github.com/tendermint/tmlibs - version: ~0.3.1 + version: ~0.3.2 subpackages: - autofile - cli diff --git a/node/id.go b/node/id.go index c521aa4af..fa391f946 100644 --- a/node/id.go +++ b/node/id.go @@ -1,8 +1,9 @@ package node import ( - "github.com/tendermint/go-crypto" "time" + + "github.com/tendermint/go-crypto" ) type NodeID struct { diff --git a/p2p/listener.go b/p2p/listener.go index a382fbeda..971390974 100644 --- a/p2p/listener.go +++ b/p2p/listener.go @@ -196,7 +196,7 @@ func getUPNPExternalAddress(externalPort, internalPort int, logger log.Logger) * return NewNetAddressIPPort(ext, uint16(externalPort)) } -// TODO: use syscalls: http://pastebin.com/9exZG4rh +// TODO: use syscalls: see issue #712 func getNaiveExternalAddress(port int, settleForLocal bool, logger log.Logger) *NetAddress { addrs, err := net.InterfaceAddrs() if err != nil { diff --git a/p2p/peer.go b/p2p/peer.go index 2b986a7a7..1bdb8210a 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -7,6 +7,7 @@ import ( "time" "github.com/pkg/errors" + crypto "github.com/tendermint/go-crypto" wire "github.com/tendermint/go-wire" cmn "github.com/tendermint/tmlibs/common" diff --git a/p2p/upnp/README.md b/p2p/upnp/README.md deleted file mode 100644 index 557d05bdc..000000000 --- a/p2p/upnp/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# `tendermint/p2p/upnp` - -## Resources - -* http://www.upnp-hacks.org/upnp.html diff --git a/p2p/upnp/upnp.go b/p2p/upnp/upnp.go index 29abbe794..7d44d1e31 100644 --- a/p2p/upnp/upnp.go +++ b/p2p/upnp/upnp.go @@ -1,11 +1,9 @@ -/* -Taken from taipei-torrent - -Just enough UPnP to be able to forward ports -*/ +// Taken from taipei-torrent. +// Just enough UPnP to be able to forward ports +// For more information, see: http://www.upnp-hacks.org/upnp.html package upnp -// BUG(jae): TODO: use syscalls to get actual ourIP. http://pastebin.com/9exZG4rh +// TODO: use syscalls to get actual ourIP, see issue #712 import ( "bytes" diff --git a/rpc/client/httpclient.go b/rpc/client/httpclient.go index 7b09b5bd0..b00c97d23 100644 --- a/rpc/client/httpclient.go +++ b/rpc/client/httpclient.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/pkg/errors" + data "github.com/tendermint/go-wire/data" ctypes "github.com/tendermint/tendermint/rpc/core/types" rpcclient "github.com/tendermint/tendermint/rpc/lib/client" diff --git a/rpc/client/mock/abci_test.go b/rpc/client/mock/abci_test.go index 935f9ff94..245db6c68 100644 --- a/rpc/client/mock/abci_test.go +++ b/rpc/client/mock/abci_test.go @@ -8,13 +8,13 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tendermint/abci/example/dummy" abci "github.com/tendermint/abci/types" data "github.com/tendermint/go-wire/data" + "github.com/tendermint/tendermint/rpc/client/mock" ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/tendermint/tendermint/types" - - "github.com/tendermint/tendermint/rpc/client/mock" ) func TestABCIMock(t *testing.T) { diff --git a/rpc/client/mock/status_test.go b/rpc/client/mock/status_test.go index e4adf52ba..80ffe7b7d 100644 --- a/rpc/client/mock/status_test.go +++ b/rpc/client/mock/status_test.go @@ -5,10 +5,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - data "github.com/tendermint/go-wire/data" - ctypes "github.com/tendermint/tendermint/rpc/core/types" + data "github.com/tendermint/go-wire/data" "github.com/tendermint/tendermint/rpc/client/mock" + ctypes "github.com/tendermint/tendermint/rpc/core/types" ) func TestStatus(t *testing.T) { diff --git a/rpc/client/rpc_test.go b/rpc/client/rpc_test.go index 77de9f6e8..9bcd3de45 100644 --- a/rpc/client/rpc_test.go +++ b/rpc/client/rpc_test.go @@ -6,7 +6,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/tendermint/merkleeyes/iavl" + + "github.com/tendermint/merkleeyes/iavl" //TODO use tendermint/iavl ? "github.com/tendermint/tendermint/rpc/client" rpctest "github.com/tendermint/tendermint/rpc/test" "github.com/tendermint/tendermint/types" diff --git a/rpc/core/blocks.go b/rpc/core/blocks.go index 17b27303f..ad00060f4 100644 --- a/rpc/core/blocks.go +++ b/rpc/core/blocks.go @@ -5,7 +5,7 @@ import ( ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/tendermint/tendermint/types" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" ) // Get block headers for minHeight <= height <= maxHeight. @@ -65,12 +65,12 @@ func BlockchainInfo(minHeight, maxHeight int) (*ctypes.ResultBlockchainInfo, err if maxHeight == 0 { maxHeight = blockStore.Height() } else { - maxHeight = MinInt(blockStore.Height(), maxHeight) + maxHeight = cmn.MinInt(blockStore.Height(), maxHeight) } if minHeight == 0 { - minHeight = MaxInt(1, maxHeight-20) + minHeight = cmn.MaxInt(1, maxHeight-20) } else { - minHeight = MaxInt(minHeight, maxHeight-20) + minHeight = cmn.MaxInt(minHeight, maxHeight-20) } logger.Debug("BlockchainInfoHandler", "maxHeight", maxHeight, "minHeight", minHeight) diff --git a/rpc/core/pipe.go b/rpc/core/pipe.go index 86c6c65e1..0602689b0 100644 --- a/rpc/core/pipe.go +++ b/rpc/core/pipe.go @@ -2,14 +2,13 @@ package core import ( crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/tmlibs/log" - "github.com/tendermint/tendermint/consensus" p2p "github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/proxy" sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/state/txindex" "github.com/tendermint/tendermint/types" + "github.com/tendermint/tmlibs/log" ) //---------------------------------------------- diff --git a/rpc/core/types/responses.go b/rpc/core/types/responses.go index 6b66f1168..22c9f9ab9 100644 --- a/rpc/core/types/responses.go +++ b/rpc/core/types/responses.go @@ -6,7 +6,6 @@ import ( abci "github.com/tendermint/abci/types" "github.com/tendermint/go-crypto" "github.com/tendermint/go-wire/data" - "github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/types" ) diff --git a/rpc/core/types/responses_test.go b/rpc/core/types/responses_test.go index 8eef19799..fa0da3fdf 100644 --- a/rpc/core/types/responses_test.go +++ b/rpc/core/types/responses_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/tendermint/tendermint/p2p" ) diff --git a/rpc/grpc/api.go b/rpc/grpc/api.go index 7cfda1587..b08a7833a 100644 --- a/rpc/grpc/api.go +++ b/rpc/grpc/api.go @@ -1,11 +1,10 @@ package core_grpc import ( - core "github.com/tendermint/tendermint/rpc/core" + context "golang.org/x/net/context" abci "github.com/tendermint/abci/types" - - context "golang.org/x/net/context" + core "github.com/tendermint/tendermint/rpc/core" ) type broadcastAPI struct { diff --git a/rpc/grpc/client_server.go b/rpc/grpc/client_server.go index e6055ede3..1c6498df7 100644 --- a/rpc/grpc/client_server.go +++ b/rpc/grpc/client_server.go @@ -8,7 +8,7 @@ import ( "google.golang.org/grpc" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" ) // Start the grpcServer in a go routine @@ -40,5 +40,5 @@ func StartGRPCClient(protoAddr string) BroadcastAPIClient { } func dialerFunc(addr string, timeout time.Duration) (net.Conn, error) { - return Connect(addr) + return cmn.Connect(addr) } diff --git a/rpc/lib/Dockerfile b/rpc/lib/Dockerfile deleted file mode 100644 index a194711bf..000000000 --- a/rpc/lib/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM golang:latest - -RUN mkdir -p /go/src/github.com/tendermint/tendermint/rpc/lib -WORKDIR /go/src/github.com/tendermint/tendermint/rpc/lib - -COPY Makefile /go/src/github.com/tendermint/tendermint/rpc/lib/ -# COPY glide.yaml /go/src/github.com/tendermint/tendermint/rpc/lib/ -# COPY glide.lock /go/src/github.com/tendermint/tendermint/rpc/lib/ - -COPY . /go/src/github.com/tendermint/tendermint/rpc/lib - -RUN make get_deps diff --git a/rpc/lib/Makefile b/rpc/lib/Makefile deleted file mode 100644 index 0937558a8..000000000 --- a/rpc/lib/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -PACKAGES=$(shell go list ./... | grep -v "test") - -all: get_deps test - -test: - @echo "--> Running go test --race" - @go test --race $(PACKAGES) - @echo "--> Running integration tests" - @bash ./test/integration_test.sh - -get_deps: - @echo "--> Running go get" - @go get -v -d $(PACKAGES) - @go list -f '{{join .TestImports "\n"}}' ./... | \ - grep -v /vendor/ | sort | uniq | \ - xargs go get -v -d - -.PHONY: all test get_deps diff --git a/rpc/lib/README.md b/rpc/lib/README.md deleted file mode 100644 index de481c2f6..000000000 --- a/rpc/lib/README.md +++ /dev/null @@ -1,121 +0,0 @@ -# tendermint/rpc/lib - -[![CircleCI](https://circleci.com/gh/tendermint/tendermint/rpc/lib.svg?style=svg)](https://circleci.com/gh/tendermint/tendermint/rpc/lib) - -HTTP RPC server supporting calls via uri params, jsonrpc, and jsonrpc over websockets - -# Client Requests - -Suppose we want to expose the rpc function `HelloWorld(name string, num int)`. - -## GET (URI) - -As a GET request, it would have URI encoded parameters, and look like: - -``` -curl 'http://localhost:8008/hello_world?name="my_world"&num=5' -``` - -Note the `'` around the url, which is just so bash doesn't ignore the quotes in `"my_world"`. -This should also work: - -``` -curl http://localhost:8008/hello_world?name=\"my_world\"&num=5 -``` - -A GET request to `/` returns a list of available endpoints. -For those which take arguments, the arguments will be listed in order, with `_` where the actual value should be. - -## POST (JSONRPC) - -As a POST request, we use JSONRPC. For instance, the same request would have this as the body: - -``` -{ - "jsonrpc": "2.0", - "id": "anything", - "method": "hello_world", - "params": { - "name": "my_world", - "num": 5 - } -} -``` - -With the above saved in file `data.json`, we can make the request with - -``` -curl --data @data.json http://localhost:8008 -``` - -## WebSocket (JSONRPC) - -All requests are exposed over websocket in the same form as the POST JSONRPC. -Websocket connections are available at their own endpoint, typically `/websocket`, -though this is configurable when starting the server. - -# Server Definition - -Define some types and routes: - -``` -type ResultStatus struct { - Value string -} - -// Define some routes -var Routes = map[string]*rpcserver.RPCFunc{ - "status": rpcserver.NewRPCFunc(Status, "arg"), -} - -// an rpc function -func Status(v string) (*ResultStatus, error) { - return &ResultStatus{v}, nil -} - -``` - -Now start the server: - -``` -mux := http.NewServeMux() -rpcserver.RegisterRPCFuncs(mux, Routes) -wm := rpcserver.NewWebsocketManager(Routes, nil) -mux.HandleFunc("/websocket", wm.WebsocketHandler) -logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) -go func() { - _, err := rpcserver.StartHTTPServer("0.0.0.0:8008", mux, logger) - if err != nil { - panic(err) - } -}() - -``` - -Note that unix sockets are supported as well (eg. `/path/to/socket` instead of `0.0.0.0:8008`) - -Now see all available endpoints by sending a GET request to `0.0.0.0:8008`. -Each route is available as a GET request, as a JSONRPCv2 POST request, and via JSONRPCv2 over websockets. - - -# Examples - -* [Tendermint](https://github.com/tendermint/tendermint/blob/master/rpc/core/routes.go) -* [tm-monitor](https://github.com/tendermint/tools/blob/master/tm-monitor/rpc.go) - -## CHANGELOG - -### 0.7.0 - -BREAKING CHANGES: - -- removed `Client` empty interface -- `ClientJSONRPC#Call` `params` argument became a map -- rename `ClientURI` -> `URIClient`, `ClientJSONRPC` -> `JSONRPCClient` - -IMPROVEMENTS: - -- added `HTTPClient` interface, which can be used for both `ClientURI` -and `ClientJSONRPC` -- all params are now optional (Golang's default will be used if some param is missing) -- added `Call` method to `WSClient` (see method's doc for details) diff --git a/rpc/lib/circle.yml b/rpc/lib/circle.yml deleted file mode 100644 index 0308a4e79..000000000 --- a/rpc/lib/circle.yml +++ /dev/null @@ -1,21 +0,0 @@ -machine: - environment: - GOPATH: /home/ubuntu/.go_workspace - REPO: $GOPATH/src/github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME - hosts: - circlehost: 127.0.0.1 - localhost: 127.0.0.1 - -checkout: - post: - - rm -rf $REPO - - mkdir -p $HOME/.go_workspace/src/github.com/$CIRCLE_PROJECT_USERNAME - - mv $HOME/$CIRCLE_PROJECT_REPONAME $REPO - -dependencies: - override: - - "cd $REPO && make get_deps" - -test: - override: - - "cd $REPO && make test" diff --git a/rpc/lib/rpc_test.go b/rpc/lib/rpc_test.go index 3ceaaa39f..4e83d23ef 100644 --- a/rpc/lib/rpc_test.go +++ b/rpc/lib/rpc_test.go @@ -16,6 +16,7 @@ import ( "github.com/go-kit/kit/log/term" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tendermint/go-wire/data" client "github.com/tendermint/tendermint/rpc/lib/client" server "github.com/tendermint/tendermint/rpc/lib/server" diff --git a/state/execution_test.go b/state/execution_test.go index 2987667c5..425f59ed2 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tendermint/abci/example/dummy" crypto "github.com/tendermint/go-crypto" "github.com/tendermint/tendermint/proxy" diff --git a/state/state_test.go b/state/state_test.go index 2c19a4164..2ab2e9349 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -7,16 +7,14 @@ import ( "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" + cfg "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/types" + abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" - cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" - - cfg "github.com/tendermint/tendermint/config" - "github.com/tendermint/tendermint/types" ) // setupTestCase does setup common to all test cases diff --git a/types/genesis_test.go b/types/genesis_test.go index fe997b690..0ffce4b53 100644 --- a/types/genesis_test.go +++ b/types/genesis_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + crypto "github.com/tendermint/go-crypto" ) diff --git a/types/part_set_test.go b/types/part_set_test.go index 7088ef317..76b538c1f 100644 --- a/types/part_set_test.go +++ b/types/part_set_test.go @@ -5,7 +5,7 @@ import ( "io/ioutil" "testing" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" ) const ( @@ -15,7 +15,7 @@ const ( func TestBasicPartSet(t *testing.T) { // Construct random data of size partSize * 100 - data := RandBytes(testPartSize * 100) + data := cmn.RandBytes(testPartSize * 100) partSet := NewPartSetFromData(data, testPartSize) if len(partSet.Hash()) == 0 { @@ -65,7 +65,7 @@ func TestBasicPartSet(t *testing.T) { func TestWrongProof(t *testing.T) { // Construct random data of size partSize * 100 - data := RandBytes(testPartSize * 100) + data := cmn.RandBytes(testPartSize * 100) partSet := NewPartSetFromData(data, testPartSize) // Test adding a part with wrong data. diff --git a/types/proposal.go b/types/proposal.go index 8fe959807..8efa91b6d 100644 --- a/types/proposal.go +++ b/types/proposal.go @@ -5,7 +5,6 @@ import ( "fmt" "io" - //. "github.com/tendermint/tmlibs/common" "github.com/tendermint/go-crypto" "github.com/tendermint/go-wire" ) diff --git a/types/signable.go b/types/signable.go index 13389fef7..2134f6300 100644 --- a/types/signable.go +++ b/types/signable.go @@ -4,7 +4,7 @@ import ( "bytes" "io" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" "github.com/tendermint/tmlibs/merkle" ) @@ -19,7 +19,7 @@ func SignBytes(chainID string, o Signable) []byte { buf, n, err := new(bytes.Buffer), new(int), new(error) o.WriteSignBytes(chainID, buf, n, err) if *err != nil { - PanicCrisis(err) + cmn.PanicCrisis(err) } return buf.Bytes() } diff --git a/types/tx_test.go b/types/tx_test.go index 91cddecfe..dc99509dd 100644 --- a/types/tx_test.go +++ b/types/tx_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + wire "github.com/tendermint/go-wire" cmn "github.com/tendermint/tmlibs/common" ctest "github.com/tendermint/tmlibs/test" diff --git a/types/validator_set.go b/types/validator_set.go index 3ec389a48..0e20417a7 100644 --- a/types/validator_set.go +++ b/types/validator_set.go @@ -99,7 +99,12 @@ func (valSet *ValidatorSet) GetByAddress(address []byte) (index int, val *Valida } } +// GetByIndex returns the validator by index. +// It returns nil values if index >= len(ValidatorSet.Validators) func (valSet *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator) { + if index >= len(valSet.Validators) { + return nil, nil + } val = valSet.Validators[index] return val.Address, val.Copy() } diff --git a/types/vote.go b/types/vote.go index 164293c53..658415682 100644 --- a/types/vote.go +++ b/types/vote.go @@ -13,9 +13,9 @@ import ( var ( ErrVoteUnexpectedStep = errors.New("Unexpected step") - ErrVoteInvalidValidatorIndex = errors.New("Invalid round vote validator index") - ErrVoteInvalidValidatorAddress = errors.New("Invalid round vote validator address") - ErrVoteInvalidSignature = errors.New("Invalid round vote signature") + ErrVoteInvalidValidatorIndex = errors.New("Invalid validator index") + ErrVoteInvalidValidatorAddress = errors.New("Invalid validator address") + ErrVoteInvalidSignature = errors.New("Invalid signature") ErrVoteInvalidBlockHash = errors.New("Invalid block hash") ) diff --git a/types/vote_set.go b/types/vote_set.go index 938dbcb61..dcfb0088d 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -6,7 +6,7 @@ import ( "strings" "sync" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" ) /* @@ -51,7 +51,7 @@ type VoteSet struct { mtx sync.Mutex valSet *ValidatorSet - votesBitArray *BitArray + votesBitArray *cmn.BitArray votes []*Vote // Primary votes to share sum int64 // Sum of voting power for seen votes, discounting conflicts maj23 *BlockID // First 2/3 majority seen @@ -62,7 +62,7 @@ type VoteSet struct { // Constructs a new VoteSet struct used to accumulate votes for given height/round. func NewVoteSet(chainID string, height int, round int, type_ byte, valSet *ValidatorSet) *VoteSet { if height == 0 { - PanicSanity("Cannot make VoteSet for height == 0, doesn't make sense.") + cmn.PanicSanity("Cannot make VoteSet for height == 0, doesn't make sense.") } return &VoteSet{ chainID: chainID, @@ -70,7 +70,7 @@ func NewVoteSet(chainID string, height int, round int, type_ byte, valSet *Valid round: round, type_: type_, valSet: valSet, - votesBitArray: NewBitArray(valSet.Size()), + votesBitArray: cmn.NewBitArray(valSet.Size()), votes: make([]*Vote, valSet.Size()), sum: 0, maj23: nil, @@ -125,7 +125,7 @@ func (voteSet *VoteSet) Size() int { // NOTE: VoteSet must not be nil func (voteSet *VoteSet) AddVote(vote *Vote) (added bool, err error) { if voteSet == nil { - PanicSanity("AddVote() on nil VoteSet") + cmn.PanicSanity("AddVote() on nil VoteSet") } voteSet.mtx.Lock() defer voteSet.mtx.Unlock() @@ -140,8 +140,10 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) { blockKey := vote.BlockID.Key() // Ensure that validator index was set - if valIndex < 0 || len(valAddr) == 0 { - panic("Validator index or address was not set in vote.") + if valIndex < 0 { + return false, ErrVoteInvalidValidatorIndex + } else if len(valAddr) == 0 { + return false, ErrVoteInvalidValidatorAddress } // Make sure the step matches. @@ -186,7 +188,7 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) { } } else { if !added { - PanicSanity("Expected to add non-conflicting vote") + cmn.PanicSanity("Expected to add non-conflicting vote") } return added, nil } @@ -212,7 +214,7 @@ func (voteSet *VoteSet) addVerifiedVote(vote *Vote, blockKey string, votingPower // Already exists in voteSet.votes? if existing := voteSet.votes[valIndex]; existing != nil { if existing.BlockID.Equals(vote.BlockID) { - PanicSanity("addVerifiedVote does not expect duplicate votes") + cmn.PanicSanity("addVerifiedVote does not expect duplicate votes") } else { conflicting = existing } @@ -283,7 +285,7 @@ func (voteSet *VoteSet) addVerifiedVote(vote *Vote, blockKey string, votingPower // NOTE: VoteSet must not be nil func (voteSet *VoteSet) SetPeerMaj23(peerID string, blockID BlockID) { if voteSet == nil { - PanicSanity("SetPeerMaj23() on nil VoteSet") + cmn.PanicSanity("SetPeerMaj23() on nil VoteSet") } voteSet.mtx.Lock() defer voteSet.mtx.Unlock() @@ -316,7 +318,7 @@ func (voteSet *VoteSet) SetPeerMaj23(peerID string, blockID BlockID) { } } -func (voteSet *VoteSet) BitArray() *BitArray { +func (voteSet *VoteSet) BitArray() *cmn.BitArray { if voteSet == nil { return nil } @@ -325,7 +327,7 @@ func (voteSet *VoteSet) BitArray() *BitArray { return voteSet.votesBitArray.Copy() } -func (voteSet *VoteSet) BitArrayByBlockID(blockID BlockID) *BitArray { +func (voteSet *VoteSet) BitArrayByBlockID(blockID BlockID) *cmn.BitArray { if voteSet == nil { return nil } @@ -356,7 +358,7 @@ func (voteSet *VoteSet) GetByAddress(address []byte) *Vote { defer voteSet.mtx.Unlock() valIndex, val := voteSet.valSet.GetByAddress(address) if val == nil { - PanicSanity("GetByAddress(address) returned nil") + cmn.PanicSanity("GetByAddress(address) returned nil") } return voteSet.votes[valIndex] } @@ -454,14 +456,14 @@ func (voteSet *VoteSet) StringShort() string { func (voteSet *VoteSet) MakeCommit() *Commit { if voteSet.type_ != VoteTypePrecommit { - PanicSanity("Cannot MakeCommit() unless VoteSet.Type is VoteTypePrecommit") + cmn.PanicSanity("Cannot MakeCommit() unless VoteSet.Type is VoteTypePrecommit") } voteSet.mtx.Lock() defer voteSet.mtx.Unlock() // Make sure we have a 2/3 majority if voteSet.maj23 == nil { - PanicSanity("Cannot MakeCommit() unless a blockhash has +2/3") + cmn.PanicSanity("Cannot MakeCommit() unless a blockhash has +2/3") } // For every validator, get the precommit @@ -482,16 +484,16 @@ func (voteSet *VoteSet) MakeCommit() *Commit { 2. A peer claims to have a 2/3 majority w/ blockKey (peerMaj23=true) */ type blockVotes struct { - peerMaj23 bool // peer claims to have maj23 - bitArray *BitArray // valIndex -> hasVote? - votes []*Vote // valIndex -> *Vote - sum int64 // vote sum + peerMaj23 bool // peer claims to have maj23 + bitArray *cmn.BitArray // valIndex -> hasVote? + votes []*Vote // valIndex -> *Vote + sum int64 // vote sum } func newBlockVotes(peerMaj23 bool, numValidators int) *blockVotes { return &blockVotes{ peerMaj23: peerMaj23, - bitArray: NewBitArray(numValidators), + bitArray: cmn.NewBitArray(numValidators), votes: make([]*Vote, numValidators), sum: 0, } @@ -521,7 +523,7 @@ type VoteSetReader interface { Round() int Type() byte Size() int - BitArray() *BitArray + BitArray() *cmn.BitArray GetByIndex(int) *Vote IsCommit() bool } diff --git a/types/vote_set_test.go b/types/vote_set_test.go index 80ee6135c..5a757a00b 100644 --- a/types/vote_set_test.go +++ b/types/vote_set_test.go @@ -2,12 +2,11 @@ package types import ( "bytes" + "testing" "github.com/tendermint/go-crypto" - . "github.com/tendermint/tmlibs/common" - . "github.com/tendermint/tmlibs/test" - - "testing" + cmn "github.com/tendermint/tmlibs/common" + tst "github.com/tendermint/tmlibs/test" ) // NOTE: privValidators are in order @@ -137,7 +136,7 @@ func Test2_3Majority(t *testing.T) { // 7th validator voted for some blockhash { vote := withValidator(voteProto, privValidators[6].GetAddress(), 6) - signAddVote(privValidators[6], withBlockHash(vote, RandBytes(32)), voteSet) + signAddVote(privValidators[6], withBlockHash(vote, cmn.RandBytes(32)), voteSet) blockID, ok = voteSet.TwoThirdsMajority() if ok || !blockID.IsZero() { t.Errorf("There should be no 2/3 majority") @@ -217,7 +216,7 @@ func Test2_3MajorityRedux(t *testing.T) { // 70th validator voted for different BlockHash { vote := withValidator(voteProto, privValidators[69].GetAddress(), 69) - signAddVote(privValidators[69], withBlockHash(vote, RandBytes(32)), voteSet) + signAddVote(privValidators[69], withBlockHash(vote, cmn.RandBytes(32)), voteSet) blockID, ok = voteSet.TwoThirdsMajority() if ok || !blockID.IsZero() { t.Errorf("There should be no 2/3 majority: last vote added had different BlockHash") @@ -260,7 +259,7 @@ func TestBadVotes(t *testing.T) { // val0 votes again for some block. { vote := withValidator(voteProto, privValidators[0].GetAddress(), 0) - added, err := signAddVote(privValidators[0], withBlockHash(vote, RandBytes(32)), voteSet) + added, err := signAddVote(privValidators[0], withBlockHash(vote, cmn.RandBytes(32)), voteSet) if added || err == nil { t.Errorf("Expected VoteSet.Add to fail, conflicting vote.") } @@ -297,8 +296,8 @@ func TestBadVotes(t *testing.T) { func TestConflicts(t *testing.T) { height, round := 1, 0 voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 4, 1) - blockHash1 := RandBytes(32) - blockHash2 := RandBytes(32) + blockHash1 := cmn.RandBytes(32) + blockHash2 := cmn.RandBytes(32) voteProto := &Vote{ ValidatorAddress: nil, @@ -444,13 +443,13 @@ func TestMakeCommit(t *testing.T) { } // MakeCommit should fail. - AssertPanics(t, "Doesn't have +2/3 majority", func() { voteSet.MakeCommit() }) + tst.AssertPanics(t, "Doesn't have +2/3 majority", func() { voteSet.MakeCommit() }) // 7th voted for some other block. { vote := withValidator(voteProto, privValidators[6].GetAddress(), 6) - vote = withBlockHash(vote, RandBytes(32)) - vote = withBlockPartsHeader(vote, PartSetHeader{123, RandBytes(32)}) + vote = withBlockHash(vote, cmn.RandBytes(32)) + vote = withBlockPartsHeader(vote, PartSetHeader{123, cmn.RandBytes(32)}) signAddVote(privValidators[6], vote, voteSet) }