diff --git a/Makefile b/Makefile index 81edfd32..48270512 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 db897465..ac7cfdaf 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 4dd82a3f..e55dcf3e 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 80e87efd..1e700a86 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 1aef247a..04d62c1c 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 fba8c517..72998db8 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 a3cc726e..c58c2a4d 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 d5c9ff7b..ea905198 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 115ca2a9..65e47d12 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 356a2ff0..16bd8f20 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 8396cd23..643b2bf0 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 8edadf13..96ed46ea 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 1a5deaea..bcab4f59 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 a7ba2399..3dbf5e28 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 55a899a0..452e72e1 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 b72c0c86..8e5bd43e 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, } }