diff --git a/Makefile b/Makefile index d097ae72..6c72d063 100644 --- a/Makefile +++ b/Makefile @@ -52,13 +52,12 @@ metalinter: tools metalinter_test: tools @gometalinter --install gometalinter --vendor --deadline=600s --disable-all \ - --enable=aligncheck \ + --enable=maligned \ --enable=deadcode \ --enable=gas \ --enable=goconst \ --enable=goimports \ --enable=gosimple \ - --enable=gotype \ --enable=ineffassign \ --enable=megacheck \ --enable=misspell \ @@ -71,12 +70,13 @@ metalinter_test: tools --enable=vetshadow \ ./... - #--enable=dupl \ - #--enable=errcheck \ - #--enable=gocyclo \ - #--enable=golint \ <== comments on anything exported - #--enable=interfacer \ - #--enable=unparam \ - #--enable=vet \ + #--enable=dupl \ + #--enable=errcheck \ + #--enable=gocyclo \ + #--enable=golint \ <== comments on anything exported + #--enable=gotype \ + #--enable=interfacer \ + #--enable=unparam \ + #--enable=vet \ .PHONY: all build test fmt get_deps tools diff --git a/example/dummy/dummy.go b/example/dummy/dummy.go index 5db71f96..7e95c859 100644 --- a/example/dummy/dummy.go +++ b/example/dummy/dummy.go @@ -4,19 +4,20 @@ import ( "strings" "github.com/tendermint/abci/types" - "github.com/tendermint/merkleeyes/iavl" + wire "github.com/tendermint/go-wire" + "github.com/tendermint/iavl" cmn "github.com/tendermint/tmlibs/common" - "github.com/tendermint/tmlibs/merkle" + dbm "github.com/tendermint/tmlibs/db" ) type DummyApplication struct { types.BaseApplication - state merkle.Tree + state *iavl.VersionedTree } func NewDummyApplication() *DummyApplication { - state := iavl.NewIAVLTree(0, nil) + state := iavl.NewVersionedTree(0, dbm.NewMemDB()) return &DummyApplication{state: state} } @@ -40,28 +41,45 @@ func (app *DummyApplication) CheckTx(tx []byte) types.Result { } func (app *DummyApplication) Commit() types.Result { - hash := app.state.Hash() + // Save a new version + var hash []byte + var err error + + if app.state.Size() > 0 { + // just add one more to height (kind of arbitrarily stupid) + height := app.state.LatestVersion() + 1 + hash, err = app.state.SaveVersion(height) + if err != nil { + // if this wasn't a dummy app, we'd do something smarter + panic(err) + } + } + return types.NewResultOK(hash, "") } func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { if reqQuery.Prove { - value, proof, exists := app.state.Proof(reqQuery.Data) + value, proof, err := app.state.GetWithProof(reqQuery.Data) + // if this wasn't a dummy app, we'd do something smarter + if err != nil { + panic(err) + } resQuery.Index = -1 // TODO make Proof return index resQuery.Key = reqQuery.Data resQuery.Value = value - resQuery.Proof = proof - if exists { + resQuery.Proof = wire.BinaryBytes(proof) + if value != nil { resQuery.Log = "exists" } else { resQuery.Log = "does not exist" } return } else { - index, value, exists := app.state.Get(reqQuery.Data) + index, value := app.state.Get(reqQuery.Data) resQuery.Index = int64(index) resQuery.Value = value - if exists { + if value != nil { resQuery.Log = "exists" } else { resQuery.Log = "does not exist" diff --git a/example/dummy/dummy_test.go b/example/dummy/dummy_test.go index fa9d531b..751a2e91 100644 --- a/example/dummy/dummy_test.go +++ b/example/dummy/dummy_test.go @@ -10,8 +10,7 @@ import ( abcicli "github.com/tendermint/abci/client" "github.com/tendermint/abci/server" "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/merkleeyes/iavl" + "github.com/tendermint/iavl" cmn "github.com/tendermint/tmlibs/common" "github.com/tendermint/tmlibs/log" ) @@ -39,9 +38,10 @@ func testDummy(t *testing.T, app types.Application, tx []byte, key, value string }) require.Equal(t, types.CodeType_OK, resQuery.Code) require.Equal(t, value, string(resQuery.Value)) - proof, err := iavl.ReadProof(resQuery.Proof) + proof, err := iavl.ReadKeyExistsProof(resQuery.Proof) require.Nil(t, err) - require.True(t, proof.Verify([]byte(key), resQuery.Value, proof.RootHash)) // NOTE: we have no way to verify the RootHash + err = proof.Verify([]byte(key), resQuery.Value, proof.RootHash) + require.Nil(t, err, "%+v", err) // NOTE: we have no way to verify the RootHash } func TestDummyKV(t *testing.T) { @@ -78,6 +78,7 @@ func TestPersistentDummyInfo(t *testing.T) { t.Fatal(err) } dummy := NewPersistentDummyApplication(dir) + InitDummy(dummy) height := uint64(0) resInfo := dummy.Info(types.RequestInfo{}) @@ -113,12 +114,7 @@ func TestValSetChanges(t *testing.T) { // init with some validators total := 10 nInit := 5 - vals := make([]*types.Validator, total) - for i := 0; i < total; i++ { - pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(cmn.Fmt("test%d", i))).PubKey().Bytes() - power := cmn.RandInt() - vals[i] = &types.Validator{pubkey, uint64(power)} - } + vals := RandVals(total) // iniitalize with the first nInit dummy.InitChain(types.RequestInitChain{vals[:nInit]}) @@ -309,7 +305,8 @@ func testClient(t *testing.T, app abcicli.Client, tx []byte, key, value string) require.Nil(t, err) require.Equal(t, types.CodeType_OK, resQuery.Code) require.Equal(t, value, string(resQuery.Value)) - proof, err := iavl.ReadProof(resQuery.Proof) + proof, err := iavl.ReadKeyExistsProof(resQuery.Proof) require.Nil(t, err) - require.True(t, proof.Verify([]byte(key), resQuery.Value, proof.RootHash)) // NOTE: we have no way to verify the RootHash + err = proof.Verify([]byte(key), resQuery.Value, proof.RootHash) + require.Nil(t, err, "%+v", err) // NOTE: we have no way to verify the RootHash } diff --git a/example/dummy/helpers.go b/example/dummy/helpers.go new file mode 100644 index 00000000..55c464de --- /dev/null +++ b/example/dummy/helpers.go @@ -0,0 +1,34 @@ +package dummy + +import ( + "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" + cmn "github.com/tendermint/tmlibs/common" +) + +// RandVal creates one random validator, with a key derived +// from the input value +func RandVal(i int) *types.Validator { + pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(cmn.Fmt("test%d", i))).PubKey().Bytes() + power := cmn.RandUint16() + 1 + return &types.Validator{pubkey, uint64(power)} +} + +// RandVals returns a list of cnt validators for initializing +// the application. Note that the keys are deterministically +// derived from the index in the array, while the power is +// random (Change this if not desired) +func RandVals(cnt int) []*types.Validator { + res := make([]*types.Validator, cnt) + for i := 0; i < cnt; i++ { + res[i] = RandVal(i) + } + return res +} + +// InitDummy initializes the dummy app with some data, +// which allows tests to pass and is fine as long as you +// don't make any tx that modify the validator state +func InitDummy(app *PersistentDummyApplication) { + app.InitChain(types.RequestInitChain{RandVals(1)}) +} diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index a8bfbcf0..15fe150d 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -6,10 +6,8 @@ import ( "strconv" "strings" - "github.com/pkg/errors" "github.com/tendermint/abci/types" - wire "github.com/tendermint/go-wire" - "github.com/tendermint/merkleeyes/iavl" + "github.com/tendermint/iavl" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -23,11 +21,6 @@ const ( type PersistentDummyApplication struct { app *DummyApplication - db dbm.DB - - // latest received - // TODO: move to merkle tree? - blockHeader *types.Header // validator set changes []*types.Validator @@ -36,17 +29,17 @@ type PersistentDummyApplication struct { } func NewPersistentDummyApplication(dbDir string) *PersistentDummyApplication { - db := dbm.NewDB("dummy", "leveldb", dbDir) - lastBlock := LoadLastBlock(db) + name := "dummy" + db, err := dbm.NewGoLevelDB(name, dbDir) + if err != nil { + panic(err) + } - stateTree := iavl.NewIAVLTree(0, db) - stateTree.Load(lastBlock.AppHash) - - // log.Notice("Loaded state", "block", lastBlock.Height, "root", stateTree.Hash()) + stateTree := iavl.NewVersionedTree(500, db) + stateTree.Load() return &PersistentDummyApplication{ app: &DummyApplication{state: stateTree}, - db: db, logger: log.NewNopLogger(), } } @@ -57,9 +50,8 @@ func (app *PersistentDummyApplication) SetLogger(l log.Logger) { func (app *PersistentDummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { resInfo = app.app.Info(req) - lastBlock := LoadLastBlock(app.db) - resInfo.LastBlockHeight = lastBlock.Height - resInfo.LastBlockAppHash = lastBlock.AppHash + resInfo.LastBlockHeight = app.app.state.LatestVersion() + resInfo.LastBlockAppHash = app.app.state.Hash() return resInfo } @@ -85,19 +77,21 @@ func (app *PersistentDummyApplication) CheckTx(tx []byte) types.Result { return app.app.CheckTx(tx) } +// Commit will panic if InitChain was not called func (app *PersistentDummyApplication) Commit() types.Result { - // Save - appHash := app.app.state.Save() - app.logger.Info("Saved state", "root", appHash) - lastBlock := LastBlockInfo{ - Height: app.blockHeader.Height, - AppHash: appHash, // this hash will be in the next block header + // Save a new version for next height + height := app.app.state.LatestVersion() + 1 + var appHash []byte + var err error + + appHash, err = app.app.state.SaveVersion(height) + if err != nil { + // if this wasn't a dummy app, we'd do something smarter + panic(err) } - app.logger.Info("Saving block", "height", lastBlock.Height, "root", lastBlock.AppHash) - SaveLastBlock(app.db, lastBlock) - + app.logger.Info("Commit block", "height", height, "root", appHash) return types.NewResultOK(appHash, "") } @@ -117,9 +111,6 @@ func (app *PersistentDummyApplication) InitChain(params types.RequestInitChain) // 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) } @@ -129,41 +120,6 @@ func (app *PersistentDummyApplication) EndBlock(height uint64) (resEndBlock type return types.ResponseEndBlock{Diffs: app.changes} } -//----------------------------------------- -// persist the last block info - -var lastBlockKey = []byte("lastblock") - -type LastBlockInfo struct { - Height uint64 - AppHash []byte -} - -// Get the last block from the db -func LoadLastBlock(db dbm.DB) (lastBlock LastBlockInfo) { - buf := db.Get(lastBlockKey) - if len(buf) != 0 { - r, n, err := bytes.NewReader(buf), new(int), new(error) - wire.ReadBinaryPtr(&lastBlock, r, 0, n, err) - if *err != nil { - cmn.PanicCrisis(errors.Wrap(*err, "cannot load last block (data has been corrupted or its spec has changed)")) - } - // TODO: ensure that buf is completely read. - } - - return lastBlock -} - -func SaveLastBlock(db dbm.DB, lastBlock LastBlockInfo) { - buf, n, err := new(bytes.Buffer), new(int), new(error) - wire.WriteBinary(lastBlock, buf, n, err) - if *err != nil { - // TODO - cmn.PanicCrisis(errors.Wrap(*err, "cannot save last block")) - } - db.Set(lastBlockKey, buf.Bytes()) -} - //--------------------------------------------- // update validators diff --git a/glide.lock b/glide.lock index 7b79f0e5..cc94dbd5 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: f9c2ddad16bf8652076a93bd9f398bb498eefb2f5bd2c89a77d966ebd12feec8 -updated: 2017-09-22T10:34:17.228026799-04:00 +hash: 876bc65024f66612325ebafcedeb3e4d5014d46b339cf7583f1c00c6bac6e32c +updated: 2017-10-23T14:04:02.596189966+02:00 imports: - name: github.com/btcsuite/btcd version: b8df516b4b267acf2de46be593a9d948d1d2c420 @@ -57,17 +57,15 @@ imports: - edwards25519 - extra25519 - name: github.com/tendermint/go-crypto - version: e6ea9499ff958479e4a921850d2382eb599f204c + version: 8e7f0e7701f92206679ad093d013b9b162427631 - name: github.com/tendermint/go-wire - version: 5f88da3dbc1a72844e6dfaf274ce87f851d488eb + version: 26ee079df7fca1958da8995c727b59759b197534 subpackages: - data -- name: github.com/tendermint/merkleeyes - version: 2f6e5d31e7a35045d8d0a5895cb1fec33dd4d32b - subpackages: - - iavl +- name: github.com/tendermint/iavl + version: 721710e7aa59f61dbfbf558943a207ba3fe6b926 - name: github.com/tendermint/tmlibs - version: bffe6744ec277d60f707ab442e25513617842f8e + version: 8e5266a9ef2527e68a1571f932db8228a331b556 subpackages: - common - db @@ -75,7 +73,7 @@ imports: - merkle - process - name: github.com/urfave/cli - version: d70f47eeca3afd795160003bc6e28b001d60c67c + version: 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c - name: golang.org/x/crypto version: c7af5bf2638a1164f2eb5467c39c6cffbd13a02e subpackages: @@ -123,7 +121,7 @@ imports: - tap - transport - name: gopkg.in/go-playground/validator.v9 - version: d529ee1b0f30352444f507cc6cdac96bfd12decc + version: 6d8c18553ea1ac493d049edd6f102f52e618f085 testImports: - name: github.com/davecgh/go-spew version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 diff --git a/glide.yaml b/glide.yaml index 11379aad..e8cf8302 100644 --- a/glide.yaml +++ b/glide.yaml @@ -8,10 +8,8 @@ import: version: develop - package: github.com/tendermint/go-wire version: develop -- package: github.com/tendermint/merkleeyes +- package: github.com/tendermint/iavl version: develop - subpackages: - - iavl - package: github.com/tendermint/tmlibs version: develop subpackages: diff --git a/tests/test_cli/ex1.abci.out b/tests/test_cli/ex1.abci.out index e434944a..21c778c7 100644 --- a/tests/test_cli/ex1.abci.out +++ b/tests/test_cli/ex1.abci.out @@ -15,8 +15,8 @@ -> data.hex: 7B2273697A65223A317D > commit --> data: uü~„»×ˆíX–$ðlú‡EÑ --> data.hex: 750502FC7E84BBD788ED589624F06CFA871845D1 +-> data: IßÑ\ͬޮ—(ËûµèhŒ¥‹‘ +-> data.hex: 49DFD15CCDACDEAE9728CB01FBB5E8688CA58B91 > query "abc" -> log: exists @@ -27,8 +27,8 @@ > deliver_tx "def=xyz" > commit --> data: v9;Š.E†°iLbžËQ²†ïÕ --> data.hex: 76393B8A182E450286B0694C629ECB51B286EFD5 +-> data: p-³"€7?¿?Ÿ‰Ú* Î,Ö+ +-> data.hex: 70102DB32280373FBF3F9F89DA2A20CE2CD62B0B > query "def" -> log: exists