Merge pull request #116 from tendermint/feature/merkleeyes-to-iavl

merkleeyes to iavl
This commit is contained in:
Ethan Frey 2017-10-23 14:26:12 +02:00 committed by GitHub
commit bb9bb4aa46
8 changed files with 115 additions and 114 deletions

View File

@ -52,13 +52,12 @@ metalinter: tools
metalinter_test: tools metalinter_test: tools
@gometalinter --install @gometalinter --install
gometalinter --vendor --deadline=600s --disable-all \ gometalinter --vendor --deadline=600s --disable-all \
--enable=aligncheck \ --enable=maligned \
--enable=deadcode \ --enable=deadcode \
--enable=gas \ --enable=gas \
--enable=goconst \ --enable=goconst \
--enable=goimports \ --enable=goimports \
--enable=gosimple \ --enable=gosimple \
--enable=gotype \
--enable=ineffassign \ --enable=ineffassign \
--enable=megacheck \ --enable=megacheck \
--enable=misspell \ --enable=misspell \
@ -71,12 +70,13 @@ metalinter_test: tools
--enable=vetshadow \ --enable=vetshadow \
./... ./...
#--enable=dupl \ #--enable=dupl \
#--enable=errcheck \ #--enable=errcheck \
#--enable=gocyclo \ #--enable=gocyclo \
#--enable=golint \ <== comments on anything exported #--enable=golint \ <== comments on anything exported
#--enable=interfacer \ #--enable=gotype \
#--enable=unparam \ #--enable=interfacer \
#--enable=vet \ #--enable=unparam \
#--enable=vet \
.PHONY: all build test fmt get_deps tools .PHONY: all build test fmt get_deps tools

View File

@ -4,19 +4,20 @@ import (
"strings" "strings"
"github.com/tendermint/abci/types" "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" cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/merkle" dbm "github.com/tendermint/tmlibs/db"
) )
type DummyApplication struct { type DummyApplication struct {
types.BaseApplication types.BaseApplication
state merkle.Tree state *iavl.VersionedTree
} }
func NewDummyApplication() *DummyApplication { func NewDummyApplication() *DummyApplication {
state := iavl.NewIAVLTree(0, nil) state := iavl.NewVersionedTree(0, dbm.NewMemDB())
return &DummyApplication{state: state} return &DummyApplication{state: state}
} }
@ -40,28 +41,45 @@ func (app *DummyApplication) CheckTx(tx []byte) types.Result {
} }
func (app *DummyApplication) Commit() 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, "") return types.NewResultOK(hash, "")
} }
func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
if reqQuery.Prove { 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.Index = -1 // TODO make Proof return index
resQuery.Key = reqQuery.Data resQuery.Key = reqQuery.Data
resQuery.Value = value resQuery.Value = value
resQuery.Proof = proof resQuery.Proof = wire.BinaryBytes(proof)
if exists { if value != nil {
resQuery.Log = "exists" resQuery.Log = "exists"
} else { } else {
resQuery.Log = "does not exist" resQuery.Log = "does not exist"
} }
return return
} else { } else {
index, value, exists := app.state.Get(reqQuery.Data) index, value := app.state.Get(reqQuery.Data)
resQuery.Index = int64(index) resQuery.Index = int64(index)
resQuery.Value = value resQuery.Value = value
if exists { if value != nil {
resQuery.Log = "exists" resQuery.Log = "exists"
} else { } else {
resQuery.Log = "does not exist" resQuery.Log = "does not exist"

View File

@ -10,8 +10,7 @@ import (
abcicli "github.com/tendermint/abci/client" abcicli "github.com/tendermint/abci/client"
"github.com/tendermint/abci/server" "github.com/tendermint/abci/server"
"github.com/tendermint/abci/types" "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto" "github.com/tendermint/iavl"
"github.com/tendermint/merkleeyes/iavl"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/log" "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, types.CodeType_OK, resQuery.Code)
require.Equal(t, value, string(resQuery.Value)) require.Equal(t, value, string(resQuery.Value))
proof, err := iavl.ReadProof(resQuery.Proof) proof, err := iavl.ReadKeyExistsProof(resQuery.Proof)
require.Nil(t, err) 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) { func TestDummyKV(t *testing.T) {
@ -78,6 +78,7 @@ func TestPersistentDummyInfo(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
dummy := NewPersistentDummyApplication(dir) dummy := NewPersistentDummyApplication(dir)
InitDummy(dummy)
height := uint64(0) height := uint64(0)
resInfo := dummy.Info(types.RequestInfo{}) resInfo := dummy.Info(types.RequestInfo{})
@ -113,12 +114,7 @@ func TestValSetChanges(t *testing.T) {
// init with some validators // init with some validators
total := 10 total := 10
nInit := 5 nInit := 5
vals := make([]*types.Validator, total) vals := RandVals(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)}
}
// iniitalize with the first nInit // iniitalize with the first nInit
dummy.InitChain(types.RequestInitChain{vals[: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.Nil(t, err)
require.Equal(t, types.CodeType_OK, resQuery.Code) require.Equal(t, types.CodeType_OK, resQuery.Code)
require.Equal(t, value, string(resQuery.Value)) require.Equal(t, value, string(resQuery.Value))
proof, err := iavl.ReadProof(resQuery.Proof) proof, err := iavl.ReadKeyExistsProof(resQuery.Proof)
require.Nil(t, err) 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
} }

34
example/dummy/helpers.go Normal file
View File

@ -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)})
}

View File

@ -6,10 +6,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/pkg/errors"
"github.com/tendermint/abci/types" "github.com/tendermint/abci/types"
wire "github.com/tendermint/go-wire" "github.com/tendermint/iavl"
"github.com/tendermint/merkleeyes/iavl"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
@ -23,11 +21,6 @@ const (
type PersistentDummyApplication struct { type PersistentDummyApplication struct {
app *DummyApplication app *DummyApplication
db dbm.DB
// latest received
// TODO: move to merkle tree?
blockHeader *types.Header
// validator set // validator set
changes []*types.Validator changes []*types.Validator
@ -36,17 +29,17 @@ type PersistentDummyApplication struct {
} }
func NewPersistentDummyApplication(dbDir string) *PersistentDummyApplication { func NewPersistentDummyApplication(dbDir string) *PersistentDummyApplication {
db := dbm.NewDB("dummy", "leveldb", dbDir) name := "dummy"
lastBlock := LoadLastBlock(db) db, err := dbm.NewGoLevelDB(name, dbDir)
if err != nil {
panic(err)
}
stateTree := iavl.NewIAVLTree(0, db) stateTree := iavl.NewVersionedTree(500, db)
stateTree.Load(lastBlock.AppHash) stateTree.Load()
// log.Notice("Loaded state", "block", lastBlock.Height, "root", stateTree.Hash())
return &PersistentDummyApplication{ return &PersistentDummyApplication{
app: &DummyApplication{state: stateTree}, app: &DummyApplication{state: stateTree},
db: db,
logger: log.NewNopLogger(), logger: log.NewNopLogger(),
} }
} }
@ -57,9 +50,8 @@ func (app *PersistentDummyApplication) SetLogger(l log.Logger) {
func (app *PersistentDummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { func (app *PersistentDummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
resInfo = app.app.Info(req) resInfo = app.app.Info(req)
lastBlock := LoadLastBlock(app.db) resInfo.LastBlockHeight = app.app.state.LatestVersion()
resInfo.LastBlockHeight = lastBlock.Height resInfo.LastBlockAppHash = app.app.state.Hash()
resInfo.LastBlockAppHash = lastBlock.AppHash
return resInfo return resInfo
} }
@ -85,19 +77,21 @@ func (app *PersistentDummyApplication) CheckTx(tx []byte) types.Result {
return app.app.CheckTx(tx) return app.app.CheckTx(tx)
} }
// Commit will panic if InitChain was not called
func (app *PersistentDummyApplication) Commit() types.Result { func (app *PersistentDummyApplication) Commit() types.Result {
// Save
appHash := app.app.state.Save()
app.logger.Info("Saved state", "root", appHash)
lastBlock := LastBlockInfo{ // Save a new version for next height
Height: app.blockHeader.Height, height := app.app.state.LatestVersion() + 1
AppHash: appHash, // this hash will be in the next block header 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) app.logger.Info("Commit block", "height", height, "root", appHash)
SaveLastBlock(app.db, lastBlock)
return types.NewResultOK(appHash, "") return types.NewResultOK(appHash, "")
} }
@ -117,9 +111,6 @@ func (app *PersistentDummyApplication) InitChain(params types.RequestInitChain)
// Track the block hash and header information // Track the block hash and header information
func (app *PersistentDummyApplication) BeginBlock(params types.RequestBeginBlock) { func (app *PersistentDummyApplication) BeginBlock(params types.RequestBeginBlock) {
// update latest block info
app.blockHeader = params.Header
// reset valset changes // reset valset changes
app.changes = make([]*types.Validator, 0) app.changes = make([]*types.Validator, 0)
} }
@ -129,41 +120,6 @@ func (app *PersistentDummyApplication) EndBlock(height uint64) (resEndBlock type
return types.ResponseEndBlock{Diffs: app.changes} 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 // update validators

20
glide.lock generated
View File

@ -1,5 +1,5 @@
hash: f9c2ddad16bf8652076a93bd9f398bb498eefb2f5bd2c89a77d966ebd12feec8 hash: 876bc65024f66612325ebafcedeb3e4d5014d46b339cf7583f1c00c6bac6e32c
updated: 2017-09-22T10:34:17.228026799-04:00 updated: 2017-10-23T14:04:02.596189966+02:00
imports: imports:
- name: github.com/btcsuite/btcd - name: github.com/btcsuite/btcd
version: b8df516b4b267acf2de46be593a9d948d1d2c420 version: b8df516b4b267acf2de46be593a9d948d1d2c420
@ -57,17 +57,15 @@ imports:
- edwards25519 - edwards25519
- extra25519 - extra25519
- name: github.com/tendermint/go-crypto - name: github.com/tendermint/go-crypto
version: e6ea9499ff958479e4a921850d2382eb599f204c version: 8e7f0e7701f92206679ad093d013b9b162427631
- name: github.com/tendermint/go-wire - name: github.com/tendermint/go-wire
version: 5f88da3dbc1a72844e6dfaf274ce87f851d488eb version: 26ee079df7fca1958da8995c727b59759b197534
subpackages: subpackages:
- data - data
- name: github.com/tendermint/merkleeyes - name: github.com/tendermint/iavl
version: 2f6e5d31e7a35045d8d0a5895cb1fec33dd4d32b version: 721710e7aa59f61dbfbf558943a207ba3fe6b926
subpackages:
- iavl
- name: github.com/tendermint/tmlibs - name: github.com/tendermint/tmlibs
version: bffe6744ec277d60f707ab442e25513617842f8e version: 8e5266a9ef2527e68a1571f932db8228a331b556
subpackages: subpackages:
- common - common
- db - db
@ -75,7 +73,7 @@ imports:
- merkle - merkle
- process - process
- name: github.com/urfave/cli - name: github.com/urfave/cli
version: d70f47eeca3afd795160003bc6e28b001d60c67c version: 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
- name: golang.org/x/crypto - name: golang.org/x/crypto
version: c7af5bf2638a1164f2eb5467c39c6cffbd13a02e version: c7af5bf2638a1164f2eb5467c39c6cffbd13a02e
subpackages: subpackages:
@ -123,7 +121,7 @@ imports:
- tap - tap
- transport - transport
- name: gopkg.in/go-playground/validator.v9 - name: gopkg.in/go-playground/validator.v9
version: d529ee1b0f30352444f507cc6cdac96bfd12decc version: 6d8c18553ea1ac493d049edd6f102f52e618f085
testImports: testImports:
- name: github.com/davecgh/go-spew - name: github.com/davecgh/go-spew
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9

View File

@ -8,10 +8,8 @@ import:
version: develop version: develop
- package: github.com/tendermint/go-wire - package: github.com/tendermint/go-wire
version: develop version: develop
- package: github.com/tendermint/merkleeyes - package: github.com/tendermint/iavl
version: develop version: develop
subpackages:
- iavl
- package: github.com/tendermint/tmlibs - package: github.com/tendermint/tmlibs
version: develop version: develop
subpackages: subpackages:

View File

@ -15,8 +15,8 @@
-> data.hex: 7B2273697A65223A317D -> data.hex: 7B2273697A65223A317D
> commit > commit
-> data: uü~„»×ˆíX$ðlú‡ -> data: IßÑ\ͬޮ—(ËûµèhŒ¥
-> data.hex: 750502FC7E84BBD788ED589624F06CFA871845D1 -> data.hex: 49DFD15CCDACDEAE9728CB01FBB5E8688CA58B91
> query "abc" > query "abc"
-> log: exists -> log: exists
@ -27,8 +27,8 @@
> deliver_tx "def=xyz" > deliver_tx "def=xyz"
> commit > commit
-> data: v9;Š.E†°iLbžËQ²†ïÕ -> data: p-³"€7?¿?Ÿ‰Ú* Î,Ö+
-> data.hex: 76393B8A182E450286B0694C629ECB51B286EFD5 -> data.hex: 70102DB32280373FBF3F9F89DA2A20CE2CD62B0B
> query "def" > query "def"
-> log: exists -> log: exists