-
Notifications
You must be signed in to change notification settings - Fork 291
/
utxobackendtx.go
163 lines (146 loc) · 5.56 KB
/
utxobackendtx.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright (c) 2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain
import (
"errors"
"fmt"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/util"
)
// UtxoBackendTx represents a UtxoBackend transaction.
//
// As would be expected with a transaction, no changes will be saved to the
// underlying UtxoBackend until it has been committed. The transaction will
// only provide a view of the database at the time it was created. Transactions
// should not be long running operations.
//
// The interface contract requires that these methods are safe for concurrent
// access.
type UtxoBackendTx interface {
// Get returns the value for the given key. It returns nil if the key does
// not exist. An empty slice is returned for keys that exist but have no
// value assigned.
//
// The returned slice is safe to modify. Additionally, it is safe to modify
// the slice passed as an argument after Get returns.
Get(key []byte) ([]byte, error)
// Has returns true if the key exists.
//
// It is safe to modify the slice passed as an argument after Has returns.
Has(key []byte) (bool, error)
// Put sets the value for the given key. It overwrites any previous value
// for that key.
//
// It is safe to modify the slice passed as an argument after Put returns.
Put(key, value []byte) error
// Delete removes the given key.
//
// It is safe to modify the slice passed as an argument after Delete
// returns.
Delete(key []byte) error
// NewIterator returns an iterator for the latest snapshot of the
// transaction. The returned iterator is NOT safe for concurrent use, but
// it is safe to use multiple iterators concurrently, with each in a
// dedicated goroutine.
//
// The prefix parameter allows for slicing the iterator to only contain keys
// with the given prefix. A nil prefix is treated as a key BEFORE all keys.
//
// NOTE: The contents of any slice returned by the iterator should NOT be
// modified unless noted otherwise.
//
// The iterator must be released after use, by calling the Release method.
NewIterator(prefix []byte) UtxoBackendIterator
// Commit commits the transaction. If the returned error is not nil, then
// the transaction is not committed and can either be retried or discarded.
//
// Other methods should not be called after the transaction has been
// committed.
Commit() error
// Discard discards the transaction. This method is a noop if the
// transaction is already closed (either committed or discarded).
//
// Other methods should not be called after the transaction has been
// discarded.
Discard()
}
// levelDbUtxoBackendTx represents a UtxoBackend transaction. It wraps an
// underlying leveldb transaction and implements the UtxoBackendTx interface.
type levelDbUtxoBackendTx struct {
*leveldb.Transaction
}
// Ensure levelDbUtxoBackendTx implements the UtxoBackendTx interface.
var _ UtxoBackendTx = (*levelDbUtxoBackendTx)(nil)
// Get returns the value for the given key. It returns nil if the key does not
// exist. An empty slice is returned for keys that exist but have no value
// assigned.
//
// The returned slice is safe to modify. Additionally, it is safe to modify the
// slice passed as an argument after Get returns.
func (tx *levelDbUtxoBackendTx) Get(key []byte) ([]byte, error) {
serialized, err := tx.Transaction.Get(key, nil)
if err != nil {
if errors.Is(err, leveldb.ErrNotFound) {
return nil, nil
}
str := fmt.Sprintf("failed to get key %x from leveldb transaction", key)
return nil, convertLdbErr(err, str)
}
return serialized, nil
}
// Has returns true if the key exists.
//
// It is safe to modify the slice passed as an argument after Has returns.
func (tx *levelDbUtxoBackendTx) Has(key []byte) (bool, error) {
has, err := tx.Transaction.Has(key, nil)
if err != nil {
str := fmt.Sprintf("failed to get existence of key %x from leveldb "+
"transaction", key)
return false, convertLdbErr(err, str)
}
return has, nil
}
// Put sets the value for the given key. It overwrites any previous value for
// that key.
//
// It is safe to modify the slice passed as an argument after Put returns.
func (tx *levelDbUtxoBackendTx) Put(key, value []byte) error {
err := tx.Transaction.Put(key, value, nil)
if err != nil {
str := fmt.Sprintf("failed to put key %x (value %x) to leveldb "+
"transaction", key, value)
return convertLdbErr(err, str)
}
return nil
}
// Delete removes the given key.
//
// It is safe to modify the slice passed as an argument after Delete returns.
func (tx *levelDbUtxoBackendTx) Delete(key []byte) error {
err := tx.Transaction.Delete(key, nil)
if err != nil {
str := fmt.Sprintf("failed to delete key %x from leveldb transaction",
key)
return convertLdbErr(err, str)
}
return nil
}
// NewIterator returns an iterator for the latest snapshot of the transaction.
// The returned iterator is NOT safe for concurrent use, but it is safe to use
// multiple iterators concurrently, with each in a dedicated goroutine.
//
// The prefix parameter allows for slicing the iterator to only contain keys
// with the given prefix. A nil prefix is treated as a key BEFORE all keys.
//
// NOTE: The contents of any slice returned by the iterator should NOT be
// modified unless noted otherwise.
//
// The iterator must be released after use, by calling the Release method.
func (tx *levelDbUtxoBackendTx) NewIterator(prefix []byte) UtxoBackendIterator {
var slice *util.Range
if prefix != nil {
slice = util.BytesPrefix(prefix)
}
return tx.Transaction.NewIterator(slice, nil)
}