Skip to content

Commit 8239102

Browse files
committed
Integrate Arbo-based StateDB in vochain
Replace the IAVL-based StateDB used to store the vochain state by the new Arbo-based StateDB. This change doesn't introduce new features. Due to the change of the vochain state underlying structure, even if the same data is stored in the StateDB, the calculated hash of the state will be completely different and incompatible with the previous one. This means that this change is not compatible with a chain built with the old StateDB, and requires a chain reset to work. Change notes: - In statedb, remove SubTreeSingleConfig type and SubTreeSingle method in favour of a single config type (renamed to TreeConfig) and method. Introduced a new type TreeNonSingletonConfig that becomes a TreeConfig with the method WithKey, in order to keep different types for singleton trees configuration and non-singleton trees configuration. So now, we open a singleton tree like this: `mainTree.SubTree(OraclesCfg)` and a non-singleton tree like this: `processesTree.SubTree(CensusCfg.WithKey(pid))`. This type unification allows creating a slice of trees configuration (no matter if they are singleton or non-singleton) to easily access nested subtrees. - Added new methods to the TreeUpdate/TreeView in statedb to make it simpler to query nested trees: `DeepSubTree`, `DeepGet`, `DeepAdd` and `DeepSet`. - Replace VoteID = processID + nullifier by hash(processID + nullifier). The old VoteID was longer than 32 bytes, and that made it not friendly to be used as a key in Arbo. By hashing we obtain a 32byte that suits an Arbo key. - In VotesTree, replace storage format from (key:VoteID, value:VoteHash) to (key:VoteID, value:StateDBVote) where StateDBVote is a new protobuf model which contains { VoteHash, ProcessID, Nullifier }. This is required because now the VoteID is a hash of processID and nullifier, and thus from the VoteID we can't recover the nullifier, and we need a way to obtain the nullifier of a stored vote. - In ProcessesTree, replace storage format from (key: ProcessID, value: Process) to (key: ProcessID, value: StateDBProcess) where StateDBProcess is a new protobuf model which contains { Process, VotesRoot }. This is required because now there is a VotesTree for each Processes stored in the StateDB. To query the VotesTree at diferent blocks we need to store it's root next to the Process. - New hierarchy in the StateDB. In bold are trees. - Before: - 1 **AppTree** - 1 OracleList - 1 ValidatorList - 1 Header - 1 **ProcessTree** - N Processes indexed by ProcessID - 1 **VoteTree** - N Votes indexed by ProcessID + Nullifier - After: - 1 **MainTree** - 1 **OracleTree** - N Oracles indexed by address - 1 **ValidatorTree** - N Validators indexed by address - 1 Header - 1 **ProcessesTree** - N Processes indexed by ProcessID - 1 **VotesTree** - N Votes indexed by VoteID
1 parent 9c70c4a commit 8239102

File tree

16 files changed

+852
-536
lines changed

16 files changed

+852
-536
lines changed

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ require (
4848
github.com/tendermint/tendermint v0.34.10
4949
github.com/tendermint/tm-db v0.6.4
5050
github.com/timshannon/badgerhold/v3 v3.0.0-20210415132401-e7c90fb5919f
51-
github.com/vocdoni/arbo v0.0.0-20210831141531-de5914f453cf
51+
github.com/vocdoni/arbo v0.0.0-20210909102959-f09b0b039255
5252
github.com/vocdoni/go-external-ip v0.0.0-20210705122950-fae6195a1d44
5353
github.com/vocdoni/storage-proofs-eth-go v0.1.6
5454
go.uber.org/zap v1.18.1
55-
go.vocdoni.io/proto v1.0.4-0.20210726091234-bceaf416353b
55+
go.vocdoni.io/proto v1.0.4-0.20210910085433-e7c056b7c23a
5656
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
5757
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d
5858
google.golang.org/protobuf v1.27.1

go.sum

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1969,6 +1969,8 @@ github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMI
19691969
github.com/vocdoni/arbo v0.0.0-20210616072504-a8c7ea980892/go.mod h1:Pikn2YIz/Rt05HWs35QHdpx7IWk4E2G0KdnCX+KRsNs=
19701970
github.com/vocdoni/arbo v0.0.0-20210831141531-de5914f453cf h1:8hZXnUdi3v6hsarvQ6Qv7b0+j8UaqBrfLlKvn6JpNSI=
19711971
github.com/vocdoni/arbo v0.0.0-20210831141531-de5914f453cf/go.mod h1:qJqeB/91mJfvNHaJf04iyLpCZoroqrrjOrQFlDUn0ko=
1972+
github.com/vocdoni/arbo v0.0.0-20210909102959-f09b0b039255 h1:Gabst/0jIl3CgiywQWS5VpWsqaPuBwz0XAuMws5Pcyw=
1973+
github.com/vocdoni/arbo v0.0.0-20210909102959-f09b0b039255/go.mod h1:qJqeB/91mJfvNHaJf04iyLpCZoroqrrjOrQFlDUn0ko=
19721974
github.com/vocdoni/badgerhold/v3 v3.0.0-20210514115050-2d704df3456f h1:z7CK3k1yIutKycPY8s2ZbtwUBKMy3xPcLMh12QukLRY=
19731975
github.com/vocdoni/badgerhold/v3 v3.0.0-20210514115050-2d704df3456f/go.mod h1:BoN7UMTA/JcgmNPaoUQq6RwuixhgSrk5PmCMVMKLxpc=
19741976
github.com/vocdoni/blind-ca v0.1.4/go.mod h1:4ouWDqlvXrrNS0Csf3hKA3cuDTmKh6nP7kSXF39nT4s=
@@ -2102,8 +2104,11 @@ go.vocdoni.io/dvote v1.0.4-0.20210806163627-9494efbc5382/go.mod h1:kl66EQmAjR252
21022104
go.vocdoni.io/proto v0.1.7/go.mod h1:cyITrt7+sHmUJH06WLu69xB7LBY9c9FakFaBOe8gs/M=
21032105
go.vocdoni.io/proto v0.1.8/go.mod h1:cyITrt7+sHmUJH06WLu69xB7LBY9c9FakFaBOe8gs/M=
21042106
go.vocdoni.io/proto v0.1.9-0.20210304214308-6f7363b52750/go.mod h1:cyITrt7+sHmUJH06WLu69xB7LBY9c9FakFaBOe8gs/M=
2105-
go.vocdoni.io/proto v1.0.4-0.20210726091234-bceaf416353b h1:Xcc4GRtegTWKCwn2VKQTATrkmhy9f+Ju5teULJCRYg0=
21062107
go.vocdoni.io/proto v1.0.4-0.20210726091234-bceaf416353b/go.mod h1:QV3gKc9Zf0xHW3o8wEaqSn8iZ94UTl8gOzekxoz3kWs=
2108+
go.vocdoni.io/proto v1.0.4-0.20210909161946-f3158498ba88 h1:EJnuknmHjwPQL44d5TVOZJhzVA4oFzZT41etyaRervk=
2109+
go.vocdoni.io/proto v1.0.4-0.20210909161946-f3158498ba88/go.mod h1:QV3gKc9Zf0xHW3o8wEaqSn8iZ94UTl8gOzekxoz3kWs=
2110+
go.vocdoni.io/proto v1.0.4-0.20210910085433-e7c056b7c23a h1:7QimTKlkCY0O5KRFi0ejafFkLQze7zN0qOE/BuZosbE=
2111+
go.vocdoni.io/proto v1.0.4-0.20210910085433-e7c056b7c23a/go.mod h1:oi/WtiBFJ6QwNDv2aUQYwOnUKzYuS/fBqXF8xDNwcGo=
21072112
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
21082113
go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU=
21092114
go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=

statedb/statedb.go

Lines changed: 65 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -95,84 +95,106 @@ func subReadTx(tx db.ReadTx, path string) db.ReadTx {
9595
return prefixeddb.NewPrefixedReadTx(tx, []byte(path+"/"))
9696
}
9797

98-
// treeConfig is a unified configuration for a subTree.
99-
type treeConfig struct {
100-
parentLeafKey []byte
101-
prefix string
102-
*SubTreeConfig
103-
}
104-
10598
// GetRootFn is a function type that takes a leaf value and returns the contained root.
10699
type GetRootFn func(value []byte) ([]byte, error)
107100

108101
// SetRootFn is a function type that takes a leaf value and a root, updates the
109102
// leaf value with the new root and returns it.
110103
type SetRootFn func(value []byte, root []byte) ([]byte, error)
111104

112-
// SubTreeConfig
113-
type SubTreeConfig struct {
105+
// TreeParams are the parameters used in the constructor for a tree configuration.
106+
type TreeParams struct {
107+
// HashFunc is the hash function used in the merkle tree
108+
HashFunc arbo.HashFunction
109+
// KindID is a unique identifier that specifies what kind of tree this
110+
// is. Diferent kind of trees under the same parent tree must have
111+
// different KindIDs, as this parameter is used to build a disjoint
112+
// database prefix for each subTree under the same parent tree.
113+
KindID string
114+
// MaxLevels is the maximum number of merkle tree levels allowed.
115+
MaxLevels int
116+
// ParentLeafGetRoot is the function that takes a leaf value of the
117+
// parent at which this tree hangs, and returns the root of this tree.
118+
ParentLeafGetRoot GetRootFn
119+
// ParentLeafSetRoot is the function that takes a leaf value of the
120+
// parent at which this tree hangs, and updates it (returning it) with
121+
// the new root of this tree.
122+
ParentLeafSetRoot SetRootFn
123+
}
124+
125+
// TreeNonSingletonConfig contains the configuration used for a non-singleton subTree.
126+
type TreeNonSingletonConfig struct {
114127
hashFunc arbo.HashFunction
115128
kindID string
116129
parentLeafGetRoot GetRootFn
117130
parentLeafSetRoot SetRootFn
118131
maxLevels int
119132
}
120133

121-
// SubTreeSingleConfig contains the configuration used for a non-singleton subTree.
122-
func NewSubTreeConfig(hashFunc arbo.HashFunction, kindID string, maxLevels int,
123-
parentLeafGetRoot GetRootFn, parentLeafSetRoot SetRootFn) *SubTreeConfig {
124-
return &SubTreeConfig{
125-
hashFunc: hashFunc,
126-
kindID: kindID,
127-
parentLeafGetRoot: parentLeafGetRoot,
128-
parentLeafSetRoot: parentLeafSetRoot,
129-
maxLevels: maxLevels,
134+
// NewTreeNonSingletonConfig creates a new configuration for a non-singleton subTree.
135+
func NewTreeNonSingletonConfig(params TreeParams) *TreeNonSingletonConfig {
136+
return &TreeNonSingletonConfig{
137+
hashFunc: params.HashFunc,
138+
kindID: params.KindID,
139+
parentLeafGetRoot: params.ParentLeafGetRoot,
140+
parentLeafSetRoot: params.ParentLeafSetRoot,
141+
maxLevels: params.MaxLevels,
130142
}
131143
}
132144

133-
// treeConfig returns a unified configuration type for opening a singleton
134-
// subTree that is identified by `id`. `id` is the path in the parent tree to
135-
// the leaf that contains the subTree root.
136-
func (c *SubTreeConfig) treeConfig(id []byte) *treeConfig {
137-
return &treeConfig{
138-
parentLeafKey: id,
139-
prefix: c.kindID + string(id),
140-
SubTreeConfig: c,
145+
// HashFunc returns the hashFunc set for this SubTreeConfig
146+
func (c *TreeNonSingletonConfig) HashFunc() arbo.HashFunction {
147+
return c.hashFunc
148+
}
149+
150+
// WithKey returns a unified subTree configuration type for opening a singleton
151+
// subTree that is identified by `key`. `key` is the path in the parent tree
152+
// to the leaf that contains the subTree root.
153+
func (c *TreeNonSingletonConfig) WithKey(key []byte) TreeConfig {
154+
return TreeConfig{
155+
parentLeafKey: key,
156+
prefix: c.kindID + string(key),
157+
TreeNonSingletonConfig: c,
141158
}
142159
}
143160

144-
// SubTreeSingleConfig contains the configuration used for a singleton subTree.
145-
type SubTreeSingleConfig struct {
146-
*SubTreeConfig
161+
// TreeConfig contains the configuration used for a subTree.
162+
type TreeConfig struct {
163+
parentLeafKey []byte
164+
prefix string
165+
*TreeNonSingletonConfig
147166
}
148167

149-
// NewSubTreeSingleConfig creates a new SubTreeSingleConfig.
150-
func NewSubTreeSingleConfig(hashFunc arbo.HashFunction, kindID string, maxLevels int,
151-
parentLeafGetRoot GetRootFn, parentLeafSetRoot SetRootFn) *SubTreeSingleConfig {
152-
return &SubTreeSingleConfig{
153-
NewSubTreeConfig(hashFunc, kindID, maxLevels, parentLeafGetRoot, parentLeafSetRoot),
168+
// NewTreeSingletonConfig creates a new configuration for a singleton subTree.
169+
func NewTreeSingletonConfig(params TreeParams) TreeConfig {
170+
return TreeConfig{
171+
parentLeafKey: []byte(params.KindID),
172+
prefix: params.KindID,
173+
TreeNonSingletonConfig: NewTreeNonSingletonConfig(params),
154174
}
155175
}
156176

157177
// Key returns the key used in the parent tree in which the value that contains
158178
// the subTree root is stored. The key is the path of the parent leaf with the root.
159-
func (c *SubTreeSingleConfig) Key() []byte {
179+
func (c *TreeConfig) Key() []byte {
160180
return []byte(c.kindID)
161181
}
162182

163-
// treeConfig returns a unified configuration type for opening a subTree.
164-
func (c *SubTreeSingleConfig) treeConfig() *treeConfig {
165-
return &treeConfig{
166-
parentLeafKey: []byte(c.kindID),
167-
prefix: c.kindID,
168-
SubTreeConfig: c.SubTreeConfig,
169-
}
183+
// HashFunc returns the hashFunc set for this SubTreeSingleConfig
184+
func (c *TreeConfig) HashFunc() arbo.HashFunction {
185+
return c.hashFunc
170186
}
171187

172188
// mainTreeCfg is the subTree configuration of the mainTree. It doesn't have a
173189
// kindID because it's the top level tree. For the same reason, it doesn't
174190
// contain functions to work with the parent leaf: it doesn't have a parent.
175-
var mainTreeCfg = NewSubTreeSingleConfig(arbo.HashFunctionSha256, "", 256, nil, nil).treeConfig()
191+
var mainTreeCfg = NewTreeSingletonConfig(TreeParams{
192+
HashFunc: arbo.HashFunctionSha256,
193+
KindID: "",
194+
MaxLevels: 256,
195+
ParentLeafGetRoot: nil,
196+
ParentLeafSetRoot: nil,
197+
})
176198

177199
// StateDB is a database backed structure that holds a dynamic hierarchy of
178200
// linked merkle trees with the property that the keys and values of all merkle

statedb/statedb_test.go

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func TestStateDB(t *testing.T) {
101101
qt.Assert(t, rootView, qt.DeepEquals, root0)
102102

103103
_, err = mainTreeView.Get(keys[0])
104-
qt.Assert(t, err, qt.Equals, db.ErrKeyNotFound)
104+
qt.Assert(t, err, qt.Equals, arbo.ErrKeyNotFound)
105105
}
106106

107107
// dumpPrint(sdb.db)
@@ -142,65 +142,65 @@ func TestStateDB(t *testing.T) {
142142
}
143143

144144
// singleCfg is a test configuration for a singleton subTree
145-
var singleCfg = NewSubTreeSingleConfig(
146-
arbo.HashFunctionSha256,
147-
"single",
148-
256,
149-
func(value []byte) ([]byte, error) {
145+
var singleCfg = NewTreeSingletonConfig(TreeParams{
146+
HashFunc: arbo.HashFunctionSha256,
147+
KindID: "single",
148+
MaxLevels: 256,
149+
ParentLeafGetRoot: func(value []byte) ([]byte, error) {
150150
if len(value) != 32 {
151151
return nil, fmt.Errorf("len(value) = %v != 32", len(value))
152152
}
153153
return value, nil
154154
},
155-
func(value []byte, root []byte) ([]byte, error) {
155+
ParentLeafSetRoot: func(value []byte, root []byte) ([]byte, error) {
156156
if len(value) != 32 {
157157
return nil, fmt.Errorf("len(value) = %v != 32", len(value))
158158
}
159159
return root, nil
160160
},
161-
)
161+
})
162162

163163
// multiACfg is a test configuration for a non-singleton subtTree whose root is
164164
// stored in a leaf alongside another root (multiB)
165-
var multiACfg = NewSubTreeConfig(
166-
arbo.HashFunctionSha256,
167-
"multia",
168-
256,
169-
func(value []byte) ([]byte, error) {
165+
var multiACfg = NewTreeNonSingletonConfig(TreeParams{
166+
HashFunc: arbo.HashFunctionSha256,
167+
KindID: "multia",
168+
MaxLevels: 256,
169+
ParentLeafGetRoot: func(value []byte) ([]byte, error) {
170170
if len(value) != 64 {
171171
return nil, fmt.Errorf("len(value) = %v != 64", len(value))
172172
}
173173
return value[:32], nil
174174
},
175-
func(value []byte, root []byte) ([]byte, error) {
175+
ParentLeafSetRoot: func(value []byte, root []byte) ([]byte, error) {
176176
if len(value) != 64 {
177177
return nil, fmt.Errorf("len(value) = %v != 64", len(value))
178178
}
179179
copy(value[:32], root)
180180
return value, nil
181181
},
182-
)
182+
})
183183

184184
// multiBCfg is a test configuration for a non-singleton subtTree whose root is
185185
// stored in a leaf alongside another root (multiA)
186-
var multiBCfg = NewSubTreeConfig(
187-
arbo.HashFunctionPoseidon,
188-
"multib",
189-
256,
190-
func(value []byte) ([]byte, error) {
186+
var multiBCfg = NewTreeNonSingletonConfig(TreeParams{
187+
HashFunc: arbo.HashFunctionPoseidon,
188+
KindID: "multib",
189+
MaxLevels: 256,
190+
ParentLeafGetRoot: func(value []byte) ([]byte, error) {
191191
if len(value) != 64 {
192192
return nil, fmt.Errorf("len(value) = %v != 64", len(value))
193193
}
194194
return value[32:], nil
195195
},
196-
func(value []byte, root []byte) ([]byte, error) {
196+
ParentLeafSetRoot: func(value []byte, root []byte) ([]byte, error) {
197197
if len(value) != 64 {
198198
return nil, fmt.Errorf("len(value) = %v != 64", len(value))
199199
}
200200
copy(value[32:], root)
201201
return value, nil
202202
},
203-
)
203+
})
204204

205205
func TestSubTree(t *testing.T) {
206206
// In this test we have:
@@ -218,7 +218,7 @@ func TestSubTree(t *testing.T) {
218218
// Crete the leaf in mainTree which contains the root of the single
219219
qt.Assert(t, mainTree.Add(singleCfg.Key(), emptyHash), qt.IsNil)
220220
// treePrint(mainTree.tree, mainTree.txTree, "main")
221-
single, err := mainTree.SubTreeSingle(singleCfg)
221+
single, err := mainTree.SubTree(singleCfg)
222222
qt.Assert(t, err, qt.IsNil)
223223
// We add two key-values to the single tree
224224
qt.Assert(t, single.Add([]byte("key0"), []byte("value0")), qt.IsNil)
@@ -231,11 +231,11 @@ func TestSubTree(t *testing.T) {
231231
// (multiA_id, multiB_id)
232232
qt.Assert(t, mainTree.Add(id, make([]byte, 32*2)), qt.IsNil)
233233
// treePrint(mainTree.tree, mainTree.txTree, "main")
234-
multiA, err := mainTree.SubTree(id, multiACfg)
234+
multiA, err := mainTree.SubTree(multiACfg.WithKey(id))
235235
qt.Assert(t, err, qt.IsNil)
236236
// We add one key-value to multiA
237237
qt.Assert(t, multiA.Add([]byte("key2"), []byte("value2")), qt.IsNil)
238-
multiB, err := mainTree.SubTree(id, multiBCfg)
238+
multiB, err := mainTree.SubTree(multiBCfg.WithKey(id))
239239
qt.Assert(t, err, qt.IsNil)
240240
// We add one key-value to multiB
241241
qt.Assert(t, multiB.Add([]byte("key3"), []byte("value3")), qt.IsNil)
@@ -251,7 +251,7 @@ func TestSubTree(t *testing.T) {
251251
qt.Assert(t, err, qt.IsNil)
252252

253253
// Expect the two key-values in single
254-
single, err := mainTreeView.SubTreeSingle(singleCfg)
254+
single, err := mainTreeView.SubTree(singleCfg)
255255
qt.Assert(t, err, qt.IsNil)
256256
v0, err := single.Get([]byte("key0"))
257257
qt.Assert(t, err, qt.IsNil)
@@ -261,7 +261,7 @@ func TestSubTree(t *testing.T) {
261261
qt.Assert(t, v1, qt.DeepEquals, []byte("value1"))
262262

263263
// Expect the key-value in multiA
264-
multiA, err := mainTreeView.SubTree(id, multiACfg)
264+
multiA, err := mainTreeView.SubTree(multiACfg.WithKey(id))
265265
qt.Assert(t, err, qt.IsNil)
266266
// dumpPrint(multiA.tree.DB())
267267
// treePrint(multiA.tree, nil, "multiA")
@@ -270,7 +270,7 @@ func TestSubTree(t *testing.T) {
270270
qt.Assert(t, v2, qt.DeepEquals, []byte("value2"))
271271

272272
// Expect the key-value in multiB
273-
multiB, err := mainTreeView.SubTree(id, multiBCfg)
273+
multiB, err := mainTreeView.SubTree(multiBCfg.WithKey(id))
274274
qt.Assert(t, err, qt.IsNil)
275275
v3, err := multiB.Get([]byte("key3"))
276276
qt.Assert(t, err, qt.IsNil)
@@ -288,20 +288,20 @@ func TestSubTree(t *testing.T) {
288288
qt.Assert(t, err, qt.IsNil)
289289

290290
// Expect that mainTree's leaf for single == single.Root
291-
single, err := mainTreeView.SubTreeSingle(singleCfg)
291+
single, err := mainTreeView.SubTree(singleCfg)
292292
qt.Assert(t, err, qt.IsNil)
293293
singleRoot, err := single.Root()
294294
qt.Assert(t, err, qt.IsNil)
295295
qt.Assert(t, singleParentLeaf, qt.DeepEquals, singleRoot)
296296

297297
// Expect that mainTree's leaf for id == multiA.Root | multiB.Root
298-
multiA, err := mainTreeView.SubTree(id, multiACfg)
298+
multiA, err := mainTreeView.SubTree(multiACfg.WithKey(id))
299299
qt.Assert(t, err, qt.IsNil)
300300
multiARoot, err := multiA.Root()
301301
qt.Assert(t, err, qt.IsNil)
302302
qt.Assert(t, multiParentLeaf[:32], qt.DeepEquals, multiARoot)
303303

304-
multiB, err := mainTreeView.SubTree(id, multiBCfg)
304+
multiB, err := mainTreeView.SubTree(multiBCfg.WithKey(id))
305305
qt.Assert(t, err, qt.IsNil)
306306
multiBRoot, err := multiB.Root()
307307
qt.Assert(t, err, qt.IsNil)
@@ -327,7 +327,7 @@ func TestNoState(t *testing.T) {
327327
mainTreeRoot, err := mainTree.Root()
328328
qt.Assert(t, err, qt.IsNil)
329329

330-
single, err := mainTree.SubTreeSingle(singleCfg)
330+
single, err := mainTree.SubTree(singleCfg)
331331
qt.Assert(t, err, qt.IsNil)
332332
singleRoot, err := single.Root()
333333
qt.Assert(t, err, qt.IsNil)
@@ -358,7 +358,7 @@ func TestNoState(t *testing.T) {
358358
qt.Assert(t, v0, qt.DeepEquals, []byte("value0"))
359359

360360
// single root hasn't changed
361-
single, err := mainTreeView.SubTreeSingle(singleCfg)
361+
single, err := mainTreeView.SubTree(singleCfg)
362362
qt.Assert(t, err, qt.IsNil)
363363
singleRoot1, err := single.Root()
364364
qt.Assert(t, err, qt.IsNil)

0 commit comments

Comments
 (0)