@@ -2,27 +2,103 @@ package app
2
2
3
3
import (
4
4
"fmt"
5
+ "path"
5
6
6
7
abci "github.com/tendermint/abci/types"
7
- . "github.com/tendermint/go-common"
8
+ cmn "github.com/tendermint/go-common"
9
+ dbm "github.com/tendermint/go-db"
8
10
"github.com/tendermint/go-merkle"
9
11
"github.com/tendermint/go-wire"
10
12
)
11
13
12
14
type MerkleEyesApp struct {
13
- state State
15
+ abci.BaseApplication
16
+
17
+ state State
18
+ db dbm.DB
19
+ height uint64
20
+ }
21
+
22
+ // just make sure we really are an application, if the interface
23
+ // ever changes in the future
24
+ func (m * MerkleEyesApp ) assertApplication () abci.Application {
25
+ return m
26
+ }
27
+
28
+ var eyesStateKey = []byte ("merkleeyes:state" ) // Database key for merkle tree save value db values
29
+
30
+ type MerkleEyesState struct {
31
+ Hash []byte
32
+ Height uint64
14
33
}
15
34
16
- func NewMerkleEyesApp () * MerkleEyesApp {
17
- tree := merkle .NewIAVLTree (
18
- 0 ,
19
- nil ,
20
- )
21
- return & MerkleEyesApp {state : NewState (tree )}
35
+ const (
36
+ WriteSet byte = 0x01
37
+ WriteRem byte = 0x02
38
+ )
39
+
40
+ func NewMerkleEyesApp (dbName string , cacheSize int ) * MerkleEyesApp {
41
+ // start at 1 so the height returned by query is for the
42
+ // next block, ie. the one that includes the AppHash for our current state
43
+ initialHeight := uint64 (1 )
44
+
45
+ // Non-persistent case
46
+ if dbName == "" {
47
+ tree := merkle .NewIAVLTree (
48
+ 0 ,
49
+ nil ,
50
+ )
51
+ return & MerkleEyesApp {
52
+ state : NewState (tree , false ),
53
+ db : nil ,
54
+ height : initialHeight ,
55
+ }
56
+ }
57
+
58
+ // Setup the persistent merkle tree
59
+ empty , _ := cmn .IsDirEmpty (path .Join (dbName , dbName + ".db" ))
60
+
61
+ // Open the db, if the db doesn't exist it will be created
62
+ db := dbm .NewDB (dbName , dbm .LevelDBBackendStr , dbName )
63
+
64
+ // Load Tree
65
+ tree := merkle .NewIAVLTree (cacheSize , db )
66
+
67
+ if empty {
68
+ fmt .Println ("no existing db, creating new db" )
69
+ db .Set (eyesStateKey , wire .BinaryBytes (MerkleEyesState {
70
+ Hash : tree .Save (),
71
+ Height : initialHeight ,
72
+ }))
73
+ } else {
74
+ fmt .Println ("loading existing db" )
75
+ }
76
+
77
+ // Load merkle state
78
+ eyesStateBytes := db .Get (eyesStateKey )
79
+ var eyesState MerkleEyesState
80
+ err := wire .ReadBinaryBytes (eyesStateBytes , & eyesState )
81
+ if err != nil {
82
+ fmt .Println ("error reading MerkleEyesState" )
83
+ panic (err .Error ())
84
+ }
85
+ tree .Load (eyesState .Hash )
86
+
87
+ return & MerkleEyesApp {
88
+ state : NewState (tree , true ),
89
+ db : db ,
90
+ height : eyesState .Height ,
91
+ }
92
+ }
93
+
94
+ func (app * MerkleEyesApp ) CloseDB () {
95
+ if app .db != nil {
96
+ app .db .Close ()
97
+ }
22
98
}
23
99
24
100
func (app * MerkleEyesApp ) Info () abci.ResponseInfo {
25
- return abci.ResponseInfo {Data : Fmt ("size:%v" , app .state .Committed ().Size ())}
101
+ return abci.ResponseInfo {Data : cmn . Fmt ("size:%v" , app .state .Committed ().Size ())}
26
102
}
27
103
28
104
func (app * MerkleEyesApp ) SetOption (key string , value string ) (log string ) {
@@ -31,113 +107,121 @@ func (app *MerkleEyesApp) SetOption(key string, value string) (log string) {
31
107
32
108
func (app * MerkleEyesApp ) DeliverTx (tx []byte ) abci.Result {
33
109
tree := app .state .Append ()
34
- return app .DoTx (tree , tx )
110
+ return app .doTx (tree , tx )
35
111
}
36
112
37
113
func (app * MerkleEyesApp ) CheckTx (tx []byte ) abci.Result {
38
114
tree := app .state .Check ()
39
- return app .DoTx (tree , tx )
115
+ return app .doTx (tree , tx )
40
116
}
41
117
42
- func (app * MerkleEyesApp ) DoTx (tree merkle.Tree , tx []byte ) abci.Result {
118
+ func (app * MerkleEyesApp ) doTx (tree merkle.Tree , tx []byte ) abci.Result {
43
119
if len (tx ) == 0 {
44
120
return abci .ErrEncodingError .SetLog ("Tx length cannot be zero" )
45
121
}
46
122
typeByte := tx [0 ]
47
123
tx = tx [1 :]
48
124
switch typeByte {
49
- case 0x01 : // Set
125
+ case WriteSet : // Set
50
126
key , n , err := wire .GetByteSlice (tx )
51
127
if err != nil {
52
- return abci .ErrEncodingError .SetLog (Fmt ("Error getting key: %v" , err .Error ()))
128
+ return abci .ErrEncodingError .SetLog (cmn . Fmt ("Error reading key: %v" , err .Error ()))
53
129
}
54
130
tx = tx [n :]
55
131
value , n , err := wire .GetByteSlice (tx )
56
132
if err != nil {
57
- return abci .ErrEncodingError .SetLog (Fmt ("Error getting value: %v" , err .Error ()))
133
+ return abci .ErrEncodingError .SetLog (cmn . Fmt ("Error reading value: %v" , err .Error ()))
58
134
}
59
135
tx = tx [n :]
60
136
if len (tx ) != 0 {
61
- return abci .ErrEncodingError .SetLog (Fmt ("Got bytes left over" ))
137
+ return abci .ErrEncodingError .SetLog (cmn . Fmt ("Got bytes left over" ))
62
138
}
139
+
63
140
tree .Set (key , value )
64
- fmt .Println ("SET" , Fmt ("%X" , key ), Fmt ("%X" , value ))
65
- case 0x02 : // Remove
141
+ // fmt.Println("SET", cmn. Fmt("%X", key), cmn. Fmt("%X", value))
142
+ case WriteRem : // Remove
66
143
key , n , err := wire .GetByteSlice (tx )
67
144
if err != nil {
68
- return abci .ErrEncodingError .SetLog (Fmt ("Error getting key: %v" , err .Error ()))
145
+ return abci .ErrEncodingError .SetLog (cmn . Fmt ("Error reading key: %v" , err .Error ()))
69
146
}
70
147
tx = tx [n :]
71
148
if len (tx ) != 0 {
72
- return abci .ErrEncodingError .SetLog (Fmt ("Got bytes left over" ))
149
+ return abci .ErrEncodingError .SetLog (cmn . Fmt ("Got bytes left over" ))
73
150
}
74
151
tree .Remove (key )
75
152
default :
76
- return abci .ErrUnknownRequest .SetLog (Fmt ("Unexpected Tx type byte %X" , typeByte ))
153
+ return abci .ErrUnknownRequest .SetLog (cmn . Fmt ("Unexpected Tx type byte %X" , typeByte ))
77
154
}
78
155
return abci .OK
79
156
}
80
157
81
158
func (app * MerkleEyesApp ) Commit () abci.Result {
159
+
82
160
hash := app .state .Commit ()
161
+
162
+ app .height ++
163
+ if app .db != nil {
164
+ app .db .Set (eyesStateKey , wire .BinaryBytes (MerkleEyesState {
165
+ Hash : hash ,
166
+ Height : app .height ,
167
+ }))
168
+ }
169
+
83
170
if app .state .Committed ().Size () == 0 {
84
171
return abci .NewResultOK (nil , "Empty hash for empty tree" )
85
172
}
86
173
return abci .NewResultOK (hash , "" )
87
174
}
88
175
89
- func (app * MerkleEyesApp ) Query (query [] byte ) abci.Result {
90
- if len (query ) == 0 {
91
- return abci . OK
176
+ func (app * MerkleEyesApp ) Query (reqQuery abci. RequestQuery ) ( resQuery abci.ResponseQuery ) {
177
+ if len (reqQuery . Data ) == 0 {
178
+ return
92
179
}
93
180
tree := app .state .Committed ()
94
181
95
- typeByte := query [0 ]
96
- query = query [1 :]
97
- switch typeByte {
98
- case 0x01 : // Get by key
99
- key , n , err := wire .GetByteSlice (query )
100
- if err != nil {
101
- return abci .ErrEncodingError .SetLog (Fmt ("Error getting key: %v" , err .Error ()))
102
- }
103
- query = query [n :]
104
- if len (query ) != 0 {
105
- return abci .ErrEncodingError .SetLog (Fmt ("Got bytes left over" ))
106
- }
107
- _ , value , _ := tree .Get (key )
108
- return abci .NewResultOK (value , "" )
109
- case 0x02 : // Get by index
110
- index , n , err := wire .GetVarint (query )
111
- if err != nil {
112
- return abci .ErrEncodingError .SetLog (Fmt ("Error getting index: %v" , err .Error ()))
113
- }
114
- query = query [n :]
115
- if len (query ) != 0 {
116
- return abci .ErrEncodingError .SetLog (Fmt ("Got bytes left over" ))
117
- }
118
- _ , value := tree .GetByIndex (index )
119
- return abci .NewResultOK (value , "" )
120
- case 0x03 : // Get size
121
- size := tree .Size ()
122
- res := wire .BinaryBytes (size )
123
- return abci .NewResultOK (res , "" )
124
- default :
125
- return abci .ErrUnknownRequest .SetLog (Fmt ("Unexpected Query type byte %X" , typeByte ))
182
+ if reqQuery .Height != 0 {
183
+ // TODO: support older commits
184
+ resQuery .Code = abci .CodeType_InternalError
185
+ resQuery .Log = "merkleeyes only supports queries on latest commit"
186
+ return
126
187
}
127
- }
128
188
129
- // Proof fulfills the ABCI app interface. key is the one for which we
130
- // request a proof. blockHeight is the height for which we want the proof.
131
- // If blockHeight is 0, return the last commit.
132
- func (app * MerkleEyesApp ) Proof (key []byte , blockHeight uint64 ) abci.Result {
133
- // TODO: support older commits - right now we don't save the info
134
- if blockHeight != 0 {
135
- return abci .ErrInternalError .SetLog ("merkleeyes only supports proofs on latest commit" )
136
- }
189
+ // set the query response height
190
+ resQuery .Height = app .height
137
191
138
- proof , exists := app .state .Committed ().Proof (key )
139
- if ! exists {
140
- return abci .NewResultOK (nil , "Key not found" )
192
+ switch reqQuery .Path {
193
+ case "/store" , "/key" : // Get by key
194
+ key := reqQuery .Data // Data holds the key bytes
195
+ resQuery .Key = key
196
+ if reqQuery .Prove {
197
+ value , proof , exists := tree .Proof (key )
198
+ if ! exists {
199
+ resQuery .Log = "Key not found"
200
+ }
201
+ resQuery .Value = value
202
+ resQuery .Proof = proof
203
+ // TODO: return index too?
204
+ } else {
205
+ index , value , _ := tree .Get (key )
206
+ resQuery .Value = value
207
+ resQuery .Index = int64 (index )
208
+ }
209
+
210
+ case "/index" : // Get by Index
211
+ index := wire .GetInt64 (reqQuery .Data )
212
+ key , value := tree .GetByIndex (int (index ))
213
+ resQuery .Key = key
214
+ resQuery .Index = int64 (index )
215
+ resQuery .Value = value
216
+
217
+ case "/size" : // Get size
218
+ size := tree .Size ()
219
+ sizeBytes := wire .BinaryBytes (size )
220
+ resQuery .Value = sizeBytes
221
+
222
+ default :
223
+ resQuery .Code = abci .CodeType_UnknownRequest
224
+ resQuery .Log = cmn .Fmt ("Unexpected Query path: %v" , reqQuery .Path )
141
225
}
142
- return abci . NewResultOK ( proof , "" )
226
+ return
143
227
}
0 commit comments