diff --git a/README.md b/README.md index 9621f57e7..08f4a97f3 100644 --- a/README.md +++ b/README.md @@ -12,50 +12,51 @@ Inserts and removes happen through the `DeliverTx` message, while queries happen # Formatting -A transaction is a serialized request on the key-value store, using [go-wire](https://github.com/tendermint/go-wire) -for serialization. +## Byte arrays -Each function (set/insert, remove, get-by-key, get-by-index) has a corresponding type byte: +Byte-array `B` is serialized to `Encode(B)` as follows: ``` -DeliverTx/CheckTx --------- -- 0x01 for a set -- 0x02 for a remove - -Query --------- -- 0x01 for 'by Key' -- 0x02 for 'by Index' +Len(B) := Big-Endian encoded length of B +Encode(B) = Len(Len(B)) | Len(B) | B ``` -The format of a transaction is: +So if `B = "eric"`, then `Encode(B) = 0x010465726963` -``` - -``` +## Transactions -which translates to (where `Encode()` is the `go-wire` encoding function): +There are two types of transaction, each associated with a type-byte and a list of arguments: ``` -ByteType ByteVarintSizeKey BytesVarintKey BytesKey ByteVarintSizeValue BytesVarintValue BytesValue +Set 0x01 Key, Value +Remove 0x02 Key ``` -For instance, to insert the key-value pair `(eric, clapton)`, you would submit the following bytes in an DeliverTx: +A transaction consists of the type-byte concatenated with the encoded arguments. + +For instance, to insert a key-value pair, you would submit `01 | Encode(key) | Encode(value)`. +Thus, a transaction inserting the key-value pair `(eric, clapton)` would look like: ``` -010104657269630107636c6170746f6e +0x010104657269630107636c6170746f6e ``` + Here's a session from the [abci-cli](https://tendermint.com/intro/getting-started/first-abci): ``` -> append_tx 0x010104657269630107636c6170746f6e --> code: OK - -> query 0x01010465726963 --> code: OK --> data: {clapton} +> deliver_tx 0x010104657269630107636c6170746f6e + +> commit +-> data: ��N��٢ek�X�!a�� +-> data.hex: 978A4ED807D617D9A2651C6B0EC9588D2161C9E0 + +> query 0x65726963 +-> height: 2 +-> key: eric +-> key.hex: 65726963 +-> value: clapton +-> value.hex: 636C6170746F6E ``` # Poem diff --git a/app/app.go b/app/app.go index 75f7e31bb..08986c526 100644 --- a/app/app.go +++ b/app/app.go @@ -13,6 +13,7 @@ import ( "github.com/tendermint/tmlibs/merkle" ) +// MerkleEyesApp is a Merkle KV-store served as an ABCI app type MerkleEyesApp struct { abci.BaseApplication @@ -24,22 +25,25 @@ type MerkleEyesApp struct { // just make sure we really are an application, if the interface // ever changes in the future -func (m *MerkleEyesApp) assertApplication() abci.Application { - return m +func (app *MerkleEyesApp) assertApplication() abci.Application { + return app } var eyesStateKey = []byte("merkleeyes:state") // Database key for merkle tree save value db values +// MerkleEyesState contains the latest Merkle root hash and the number of times `Commit` has been called type MerkleEyesState struct { Hash []byte Height uint64 } +// Transaction type bytes const ( WriteSet byte = 0x01 WriteRem byte = 0x02 ) +// NewMerkleEyesApp initializes the database, loads any existing state, and returns a new MerkleEyesApp func NewMerkleEyesApp(dbName string, cacheSize int) *MerkleEyesApp { // start at 1 so the height returned by query is for the // next block, ie. the one that includes the AppHash for our current state @@ -96,14 +100,15 @@ func NewMerkleEyesApp(dbName string, cacheSize int) *MerkleEyesApp { } } +// CloseDB closes the database func (app *MerkleEyesApp) CloseDB() { if app.db != nil { app.db.Close() } } -// Info returns the height, hash and size (in the data) -// the height is the block that holds the transactions, not the apphash itself +// Info implements abci.Application. It returns the height, hash and size (in the data). +// The height is the block that holds the transactions, not the apphash itself. func (app *MerkleEyesApp) Info() abci.ResponseInfo { fmt.Printf("Info height %d hash %x\n", app.height, app.hash) return abci.ResponseInfo{ @@ -113,15 +118,18 @@ func (app *MerkleEyesApp) Info() abci.ResponseInfo { } } +// SetOption implements abci.Application func (app *MerkleEyesApp) SetOption(key string, value string) (log string) { return "No options are supported yet" } +// DeliverTx implements abci.Application func (app *MerkleEyesApp) DeliverTx(tx []byte) abci.Result { tree := app.state.Append() return app.doTx(tree, tx) } +// CheckTx implements abci.Application func (app *MerkleEyesApp) CheckTx(tx []byte) abci.Result { tree := app.state.Check() return app.doTx(tree, tx) @@ -167,6 +175,7 @@ func (app *MerkleEyesApp) doTx(tree merkle.Tree, tx []byte) abci.Result { return abci.OK } +// Commit implements abci.Application func (app *MerkleEyesApp) Commit() abci.Result { app.hash = app.state.Hash() @@ -193,6 +202,7 @@ func (app *MerkleEyesApp) Commit() abci.Result { return abci.NewResultOK(app.hash, "") } +// Query implements abci.Application func (app *MerkleEyesApp) Query(reqQuery abci.RequestQuery) (resQuery abci.ResponseQuery) { if len(reqQuery.Data) == 0 { return