Skip to content

Commit

Permalink
Merge branch 'develop' into fix-restart-height
Browse files Browse the repository at this point in the history
  • Loading branch information
ebuchman committed Jun 21, 2017
2 parents e811189 + c53aeeb commit 09f8bf8
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 30 deletions.
53 changes: 27 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`

```
<TypeByte> <Encode(key)> <Encode(value)>
```
## 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
Expand Down
18 changes: 14 additions & 4 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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{
Expand All @@ -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)
Expand Down Expand Up @@ -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()
Expand All @@ -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
Expand Down

0 comments on commit 09f8bf8

Please sign in to comment.