diff --git a/Makefile b/Makefile index 81edfd32f..482705125 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ dist: test: @echo "--> Running go test" - @go test -v $(PACKAGES) + @go test $(PACKAGES) test_race: @echo "--> Running go test --race" diff --git a/blockchain/store.go b/blockchain/store.go index db8974651..ac7cfdafc 100644 --- a/blockchain/store.go +++ b/blockchain/store.go @@ -64,12 +64,12 @@ func (bs *BlockStore) LoadBlock(height int) *types.Block { if r == nil { return nil } - meta := wire.ReadBinary(&types.BlockMeta{}, r, 0, &n, &err).(*types.BlockMeta) + blockMeta := wire.ReadBinary(&types.BlockMeta{}, r, 0, &n, &err).(*types.BlockMeta) if err != nil { PanicCrisis(Fmt("Error reading block meta: %v", err)) } bytez := []byte{} - for i := 0; i < meta.PartsHeader.Total; i++ { + for i := 0; i < blockMeta.BlockID.PartsHeader.Total; i++ { part := bs.LoadBlockPart(height, i) bytez = append(bytez, part.Bytes...) } @@ -101,11 +101,11 @@ func (bs *BlockStore) LoadBlockMeta(height int) *types.BlockMeta { if r == nil { return nil } - meta := wire.ReadBinary(&types.BlockMeta{}, r, 0, &n, &err).(*types.BlockMeta) + blockMeta := wire.ReadBinary(&types.BlockMeta{}, r, 0, &n, &err).(*types.BlockMeta) if err != nil { PanicCrisis(Fmt("Error reading block meta: %v", err)) } - return meta + return blockMeta } // The +2/3 and other Precommit-votes for block at `height`. @@ -154,8 +154,8 @@ func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, s } // Save block meta - meta := types.NewBlockMeta(block, blockParts) - metaBytes := wire.BinaryBytes(meta) + blockMeta := types.NewBlockMeta(block, blockParts) + metaBytes := wire.BinaryBytes(blockMeta) bs.db.Set(calcBlockMetaKey(height), metaBytes) // Save block parts diff --git a/consensus/mempool_test.go b/consensus/mempool_test.go index 4dd82a3f1..e55dcf3e6 100644 --- a/consensus/mempool_test.go +++ b/consensus/mempool_test.go @@ -114,6 +114,8 @@ func TestRmBadTx(t *testing.T) { // CounterApplication that maintains a mempool state and resets it upon commit type CounterApplication struct { + abci.BaseApplication + txCount int mempoolTxCount int } @@ -126,10 +128,6 @@ func (app *CounterApplication) Info() abci.ResponseInfo { return abci.ResponseInfo{Data: Fmt("txs:%v", app.txCount)} } -func (app *CounterApplication) SetOption(key string, value string) (log string) { - return "" -} - func (app *CounterApplication) DeliverTx(tx []byte) abci.Result { return runTx(tx, &app.txCount) } @@ -160,8 +158,3 @@ func (app *CounterApplication) Commit() abci.Result { return abci.NewResultOK(hash, "") } } - -func (app *CounterApplication) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQuery) { - resQuery.Log = "Query is not supported" - return -} diff --git a/consensus/reactor.go b/consensus/reactor.go index 80e87efd8..1e700a865 100644 --- a/consensus/reactor.go +++ b/consensus/reactor.go @@ -415,9 +415,9 @@ OUTER_LOOP: log.Warn("Failed to load block meta", "peer height", prs.Height, "our height", rs.Height, "blockstore height", conR.conS.blockStore.Height(), "pv", conR.conS.privValidator) time.Sleep(peerGossipSleepDuration) continue OUTER_LOOP - } else if !blockMeta.PartsHeader.Equals(prs.ProposalBlockPartsHeader) { + } else if !blockMeta.BlockID.PartsHeader.Equals(prs.ProposalBlockPartsHeader) { log.Info("Peer ProposalBlockPartsHeader mismatch, sleeping", - "peerHeight", prs.Height, "blockPartsHeader", blockMeta.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader) + "peerHeight", prs.Height, "blockPartsHeader", blockMeta.BlockID.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader) time.Sleep(peerGossipSleepDuration) continue OUTER_LOOP } @@ -425,7 +425,7 @@ OUTER_LOOP: part := conR.conS.blockStore.LoadBlockPart(prs.Height, index) if part == nil { log.Warn("Could not load part", "index", index, - "peerHeight", prs.Height, "blockPartsHeader", blockMeta.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader) + "peerHeight", prs.Height, "blockPartsHeader", blockMeta.BlockID.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader) time.Sleep(peerGossipSleepDuration) continue OUTER_LOOP } diff --git a/docs/architecture/ABCI.md b/docs/architecture/ABCI.md index 1aef247a0..04d62c1ce 100644 --- a/docs/architecture/ABCI.md +++ b/docs/architecture/ABCI.md @@ -2,7 +2,7 @@ ABCI is an interface between the consensus/blockchain engine known as tendermint, and the application-specific business logic, known as an ABCi app. -The tendermint core should run unchanged for all apps. Each app can customize it, the supported transactions, queries, even the validator sets and hwo to handle staking / slashing stake. This customization is achieved by implementing the ABCi app to send the proper information to the tendermint engine to perform as directed. +The tendermint core should run unchanged for all apps. Each app can customize it, the supported transactions, queries, even the validator sets and how to handle staking / slashing stake. This customization is achieved by implementing the ABCi app to send the proper information to the tendermint engine to perform as directed. To understand this decision better, think of the design of the tendermint engine. diff --git a/docs/architecture/merkle.md b/docs/architecture/merkle.md index fba8c5177..72998db88 100644 --- a/docs/architecture/merkle.md +++ b/docs/architecture/merkle.md @@ -11,7 +11,7 @@ What are some of the requirements of this store: * We must only persist complete blocks, so when we come up after a crash we are at the state of block N or N+1, but not in-between these two states. * It must allow us to read/write from one uncommited state (working state), while serving other queries from the last commited state. And a way to determine which one to serve for each client. * It must allow us to hold references to old state, to allow providing proofs from 20 blocks ago. We can define some limits as to the maximum time to hold this data. -* We provide in process binding in the go-lanaguage +* We provide in process binding in Go * We provide language-agnostic bindings when running the data store as it's own process. diff --git a/glide.lock b/glide.lock index a3cc726e8..c58c2a4d8 100644 --- a/glide.lock +++ b/glide.lock @@ -1,12 +1,10 @@ hash: e283934fbbd221161d53a918db9e49db8c5be2b8929592b05ffe6b72c2ef0ab1 -updated: 2017-01-27T22:32:42.896956819-08:00 +updated: 2017-02-14T17:07:40.028389369-05:00 imports: - name: github.com/btcsuite/btcd - version: afec1bd1245a4a19e6dfe1306974b733e7cbb9b8 + version: d06c0bb181529331be8f8d9350288c420d9e60e4 subpackages: - btcec -- name: github.com/btcsuite/fastsha256 - version: 637e656429416087660c84436a2a035d69d54e2e - name: github.com/BurntSushi/toml version: 99064174e013895bbd9b025c31100bd1d9b590ca - name: github.com/ebuchman/fail-test @@ -14,27 +12,27 @@ imports: - name: github.com/go-stack/stack version: 100eb0c0a9c5b306ca2fb4f165df21d80ada4b82 - name: github.com/gogo/protobuf - version: f9114dace7bd920b32f943b3c73fafbcbab2bf31 + version: 2221ff550f109ae54cb617c0dc6ac62658c418d7 subpackages: - proto - name: github.com/golang/protobuf - version: 1f49d83d9aa00e6ce4fc8258c71cc7786aec968a + version: 8ee79997227bf9b34611aee7946ae64735e6fd93 subpackages: - proto - name: github.com/golang/snappy - version: d9eb7a3d35ec988b8585d4a0068e462c27d28380 + version: 7db9049039a047d955fe8c19b83c8ff5abd765c7 - name: github.com/gorilla/websocket - version: 3ab3a8b8831546bd18fd182c20687ca853b2bb13 + version: 804cb600d06b10672f2fbc0a336a7bee507a428e - name: github.com/jmhodges/levigo version: c42d9e0ca023e2198120196f842701bb4c55d7b9 - name: github.com/mattn/go-colorable - version: ed8eb9e318d7a84ce5915b495b7d35e0cfe7b5a8 + version: 5411d3eea5978e6cdc258b30de592b60df6aba96 - name: github.com/mattn/go-isatty - version: 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8 + version: 281032e84ae07510239465db46bf442aa44b953a - name: github.com/spf13/pflag - version: 5ccb023bc27df288a957c5e994cd44fd19619465 + version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7 - name: github.com/syndtr/goleveldb - version: 6ae1797c0b42b9323fc27ff7dcf568df88f2f33d + version: 23851d93a2292dcc56e71a18ec9e0624d84a0f65 subpackages: - leveldb - leveldb/cache @@ -49,12 +47,11 @@ imports: - leveldb/table - leveldb/util - name: github.com/tendermint/abci - version: 8df0bc3a40ccad0d2be10e33c62c404e65c92502 + version: 31bdda27ad80e47d372e4b9e4acfd4c0ef81d3e4 subpackages: - client - example/counter - example/dummy - - example/nil - server - types - name: github.com/tendermint/ed25519 @@ -85,7 +82,7 @@ imports: - name: github.com/tendermint/go-logger version: cefb3a45c0bf3c493a04e9bcd9b1540528be59f2 - name: github.com/tendermint/go-merkle - version: 653cb1f631528351ddbc359b994eb0c96f0341cd + version: 9f20e80cb188d07860caa70196dd7700659ec4a4 - name: github.com/tendermint/go-p2p version: 67c9086b7458eb45b1970483decd01cd744c477a subpackages: @@ -97,13 +94,13 @@ imports: - server - types - name: github.com/tendermint/go-wire - version: 2f3b7aafe21c80b19b6ee3210ecb3e3d07c7a471 + version: 3216ec9d47bbdf8d4fc27d22169ea86a6688bc15 - name: github.com/tendermint/log15 - version: 9545b249b3aacafa97f79e0838b02b274adc6f5f + version: ae0f3d6450da9eac7074b439c8e1c3cabf0d5ce6 subpackages: - term - name: golang.org/x/crypto - version: aa2481cbfe81d911eb62b642b7a6b5ec58bbea71 + version: 453249f01cfeb54c3d549ddb75ff152ca243f9d8 subpackages: - curve25519 - nacl/box @@ -114,20 +111,21 @@ imports: - ripemd160 - salsa20/salsa - name: golang.org/x/net - version: cfe3c2a7525b50c3d707256e371c90938cfef98a + version: 61557ac0112b576429a0df080e1c2cef5dfbb642 subpackages: - context - http2 - http2/hpack + - idna - internal/timeseries - lex/httplex - trace - name: golang.org/x/sys - version: 30de6d19a3bd89a5f38ae4028e23aaa5582648af + version: e24f485414aeafb646f6fca458b0bf869c0880a1 subpackages: - unix - name: google.golang.org/grpc - version: 50955793b0183f9de69bd78e2ec251cf20aab121 + version: cbcceb2942a489498cf22b2f918536e819d33f0a subpackages: - codes - credentials diff --git a/proxy/client.go b/proxy/client.go index d5c9ff7b1..ea9051989 100644 --- a/proxy/client.go +++ b/proxy/client.go @@ -4,11 +4,10 @@ import ( "fmt" "sync" - cfg "github.com/tendermint/go-config" abcicli "github.com/tendermint/abci/client" "github.com/tendermint/abci/example/dummy" - nilapp "github.com/tendermint/abci/example/nil" "github.com/tendermint/abci/types" + cfg "github.com/tendermint/go-config" ) // NewABCIClient returns newly connected client @@ -74,7 +73,7 @@ func DefaultClientCreator(config cfg.Config) ClientCreator { case "persistent_dummy": return NewLocalClientCreator(dummy.NewPersistentDummyApplication(config.GetString("db_dir"))) case "nilapp": - return NewLocalClientCreator(nilapp.NewNilApplication()) + return NewLocalClientCreator(types.NewBaseApplication()) default: mustConnect := false // loop retrying return NewRemoteClientCreator(addr, transport, mustConnect) diff --git a/rpc/core/blocks.go b/rpc/core/blocks.go index 115ca2a9c..65e47d125 100644 --- a/rpc/core/blocks.go +++ b/rpc/core/blocks.go @@ -44,3 +44,28 @@ func Block(height int) (*ctypes.ResultBlock, error) { block := blockStore.LoadBlock(height) return &ctypes.ResultBlock{blockMeta, block}, nil } + +//----------------------------------------------------------------------------- + +func Commit(height int) (*ctypes.ResultCommit, error) { + if height == 0 { + return nil, fmt.Errorf("Height must be greater than 0") + } + storeHeight := blockStore.Height() + if height > storeHeight { + return nil, fmt.Errorf("Height must be less than or equal to the current blockchain height") + } + + header := blockStore.LoadBlockMeta(height).Header + + // If the next block has not been committed yet, + // use a non-canonical commit + if height == storeHeight { + commit := blockStore.LoadSeenCommit(height) + return &ctypes.ResultCommit{header, commit, false}, nil + } + + // Return the canonical commit (comes from the block at height+1) + commit := blockStore.LoadBlockCommit(height) + return &ctypes.ResultCommit{header, commit, true}, nil +} diff --git a/rpc/core/pipe.go b/rpc/core/pipe.go index 356a2ff0d..16bd8f20f 100644 --- a/rpc/core/pipe.go +++ b/rpc/core/pipe.go @@ -5,10 +5,10 @@ import ( "github.com/tendermint/go-crypto" "github.com/tendermint/go-p2p" + abci "github.com/tendermint/abci/types" "github.com/tendermint/tendermint/consensus" "github.com/tendermint/tendermint/proxy" "github.com/tendermint/tendermint/types" - abci "github.com/tendermint/abci/types" ) //----------------------------------------------------- @@ -19,6 +19,8 @@ type BlockStore interface { Height() int LoadBlockMeta(height int) *types.BlockMeta LoadBlock(height int) *types.Block + LoadSeenCommit(height int) *types.Commit + LoadBlockCommit(height int) *types.Commit } type Consensus interface { diff --git a/rpc/core/routes.go b/rpc/core/routes.go index 8396cd23c..643b2bf02 100644 --- a/rpc/core/routes.go +++ b/rpc/core/routes.go @@ -18,6 +18,7 @@ var Routes = map[string]*rpc.RPCFunc{ "blockchain": rpc.NewRPCFunc(BlockchainInfoResult, "minHeight,maxHeight"), "genesis": rpc.NewRPCFunc(GenesisResult, ""), "block": rpc.NewRPCFunc(BlockResult, "height"), + "commit": rpc.NewRPCFunc(CommitResult, "height"), "validators": rpc.NewRPCFunc(ValidatorsResult, ""), "dump_consensus_state": rpc.NewRPCFunc(DumpConsensusStateResult, ""), "unconfirmed_txs": rpc.NewRPCFunc(UnconfirmedTxsResult, ""), @@ -107,6 +108,14 @@ func BlockResult(height int) (ctypes.TMResult, error) { } } +func CommitResult(height int) (ctypes.TMResult, error) { + if r, err := Commit(height); err != nil { + return nil, err + } else { + return r, nil + } +} + func ValidatorsResult() (ctypes.TMResult, error) { if r, err := Validators(); err != nil { return nil, err diff --git a/rpc/core/status.go b/rpc/core/status.go index 8edadf136..96ed46ea6 100644 --- a/rpc/core/status.go +++ b/rpc/core/status.go @@ -15,7 +15,7 @@ func Status() (*ctypes.ResultStatus, error) { ) if latestHeight != 0 { latestBlockMeta = blockStore.LoadBlockMeta(latestHeight) - latestBlockHash = latestBlockMeta.Hash + latestBlockHash = latestBlockMeta.BlockID.Hash latestAppHash = latestBlockMeta.Header.AppHash latestBlockTime = latestBlockMeta.Header.Time.UnixNano() } diff --git a/rpc/core/types/responses.go b/rpc/core/types/responses.go index 1a5deaeab..bcab4f59c 100644 --- a/rpc/core/types/responses.go +++ b/rpc/core/types/responses.go @@ -23,6 +23,12 @@ type ResultBlock struct { Block *types.Block `json:"block"` } +type ResultCommit struct { + Header *types.Header `json:"header"` + Commit *types.Commit `json:"commit"` + CanonicalCommit bool `json:"canonical"` +} + type ResultStatus struct { NodeInfo *p2p.NodeInfo `json:"node_info"` PubKey crypto.PubKey `json:"pub_key"` @@ -106,6 +112,7 @@ const ( ResultTypeGenesis = byte(0x01) ResultTypeBlockchainInfo = byte(0x02) ResultTypeBlock = byte(0x03) + ResultTypeCommit = byte(0x04) // 0x2 bytes are for the network ResultTypeStatus = byte(0x20) @@ -148,6 +155,7 @@ var _ = wire.RegisterInterface( wire.ConcreteType{&ResultGenesis{}, ResultTypeGenesis}, wire.ConcreteType{&ResultBlockchainInfo{}, ResultTypeBlockchainInfo}, wire.ConcreteType{&ResultBlock{}, ResultTypeBlock}, + wire.ConcreteType{&ResultCommit{}, ResultTypeCommit}, wire.ConcreteType{&ResultStatus{}, ResultTypeStatus}, wire.ConcreteType{&ResultNetInfo{}, ResultTypeNetInfo}, wire.ConcreteType{&ResultDialSeeds{}, ResultTypeDialSeeds}, diff --git a/state/execution.go b/state/execution.go index a7ba2399e..3dbf5e28c 100644 --- a/state/execution.go +++ b/state/execution.go @@ -6,12 +6,12 @@ import ( "github.com/ebuchman/fail-test" + abci "github.com/tendermint/abci/types" . "github.com/tendermint/go-common" cfg "github.com/tendermint/go-config" "github.com/tendermint/go-crypto" "github.com/tendermint/tendermint/proxy" "github.com/tendermint/tendermint/types" - abci "github.com/tendermint/abci/types" ) //-------------------------------------------------- @@ -393,7 +393,7 @@ func (h *Handshaker) ReplayBlocks(appHash []byte, appBlockHeight int, appConnCon var eventCache types.Fireable // nil // replay the latest block - return h.state.ApplyBlock(eventCache, appConnConsensus, block, blockMeta.PartsHeader, MockMempool{}) + return h.state.ApplyBlock(eventCache, appConnConsensus, block, blockMeta.BlockID.PartsHeader, MockMempool{}) } else if storeBlockHeight != stateBlockHeight { // unless we failed before committing or saving state (previous 2 case), // the store and state should be at the same height! diff --git a/state/execution_test.go b/state/execution_test.go index 55a899a02..452e72e1c 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -8,12 +8,12 @@ import ( "github.com/tendermint/tendermint/config/tendermint_test" // . "github.com/tendermint/go-common" + "github.com/tendermint/abci/example/dummy" cfg "github.com/tendermint/go-config" "github.com/tendermint/go-crypto" dbm "github.com/tendermint/go-db" "github.com/tendermint/tendermint/proxy" "github.com/tendermint/tendermint/types" - "github.com/tendermint/abci/example/dummy" ) var ( @@ -203,8 +203,7 @@ func (bs *mockBlockStore) LoadBlock(height int) *types.Block { return bs.chain[h func (bs *mockBlockStore) LoadBlockMeta(height int) *types.BlockMeta { block := bs.chain[height-1] return &types.BlockMeta{ - Hash: block.Hash(), - Header: block.Header, - PartsHeader: block.MakePartSet(bs.config.GetInt("block_part_size")).Header(), + BlockID: types.BlockID{block.Hash(), block.MakePartSet(bs.config.GetInt("block_part_size")).Header()}, + Header: block.Header, } } diff --git a/types/block_meta.go b/types/block_meta.go index b72c0c860..8e5bd43e5 100644 --- a/types/block_meta.go +++ b/types/block_meta.go @@ -1,15 +1,13 @@ package types type BlockMeta struct { - Hash []byte `json:"hash"` // The block hash - Header *Header `json:"header"` // The block's Header - PartsHeader PartSetHeader `json:"parts_header"` // The PartSetHeader, for transfer + BlockID BlockID `json:"block_id"` // the block hash and partsethash + Header *Header `json:"header"` // The block's Header } func NewBlockMeta(block *Block, blockParts *PartSet) *BlockMeta { return &BlockMeta{ - Hash: block.Hash(), - Header: block.Header, - PartsHeader: blockParts.Header(), + BlockID: BlockID{block.Hash(), blockParts.Header()}, + Header: block.Header, } }