github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/core/ledger/kvledger/txmgmt/statedb/statedb.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package statedb 18 19 import ( 20 "sort" 21 22 "math/big" 23 24 "encoding/json" 25 26 "github.com/inklabsfoundation/inkchain/core/ledger/kvledger/txmgmt/version" 27 "github.com/inklabsfoundation/inkchain/core/ledger/util" 28 ) 29 30 // VersionedDBProvider provides an instance of an versioned DB 31 type VersionedDBProvider interface { 32 // GetDBHandle returns a handle to a VersionedDB 33 GetDBHandle(id string) (VersionedDB, error) 34 // Close closes all the VersionedDB instances and releases any resources held by VersionedDBProvider 35 Close() 36 } 37 38 // VersionedDB lists methods that a db is supposed to implement 39 type VersionedDB interface { 40 // GetState gets the value for given namespace and key. For a chaincode, the namespace corresponds to the chaincodeId 41 GetState(namespace string, key string) (*VersionedValue, error) 42 // GetStateMultipleKeys gets the values for multiple keys in a single call 43 GetStateMultipleKeys(namespace string, keys []string) ([]*VersionedValue, error) 44 // GetStateRangeScanIterator returns an iterator that contains all the key-values between given key ranges. 45 // startKey is inclusive 46 // endKey is exclusive 47 // The returned ResultsIterator contains results of type *VersionedKV 48 GetStateRangeScanIterator(namespace string, startKey string, endKey string) (ResultsIterator, error) 49 // ExecuteQuery executes the given query and returns an iterator that contains results of type *VersionedKV. 50 ExecuteQuery(namespace, query string) (ResultsIterator, error) 51 // ApplyUpdates applies the batch to the underlying db. 52 // height is the height of the highest transaction in the Batch that 53 // a state db implementation is expected to ues as a save point 54 ApplyUpdates(batch *UpdateBatch, height *version.Height) error 55 // GetLatestSavePoint returns the height of the highest transaction upto which 56 // the state db is consistent 57 GetLatestSavePoint() (*version.Height, error) 58 // ValidateKey tests whether the key is supported by the db implementation. 59 // For instance, leveldb supports any bytes for the key while the couchdb supports only valid utf-8 string 60 ValidateKey(key string) error 61 // Open opens the db 62 Open() error 63 // Close closes the db 64 Close() 65 } 66 67 // CompositeKey encloses Namespace and Key components 68 type CompositeKey struct { 69 Namespace string 70 Key string 71 } 72 73 // VersionedValue encloses value and corresponding version 74 type VersionedValue struct { 75 Value []byte 76 Version *version.Height 77 } 78 79 // VersionedKV encloses key and corresponding VersionedValue 80 type VersionedKV struct { 81 CompositeKey 82 VersionedValue 83 } 84 85 // ResultsIterator hepls in iterates over query results 86 type ResultsIterator interface { 87 Next() (QueryResult, error) 88 Close() 89 } 90 91 // QueryResult - a general interface for supporting different types of query results. Actual types differ for different queries 92 type QueryResult interface{} 93 94 type nsUpdates struct { 95 m map[string]*VersionedValue 96 } 97 98 func newNsUpdates() *nsUpdates { 99 return &nsUpdates{make(map[string]*VersionedValue)} 100 } 101 102 // UpdateBatch encloses the details of multiple `updates` 103 type UpdateBatch struct { 104 updates map[string]*nsUpdates 105 } 106 107 // NewUpdateBatch constructs an instance of a Batch 108 func NewUpdateBatch() *UpdateBatch { 109 return &UpdateBatch{make(map[string]*nsUpdates)} 110 } 111 112 // Get returns the VersionedValue for the given namespace and key 113 func (batch *UpdateBatch) Get(ns string, key string) *VersionedValue { 114 nsUpdates, ok := batch.updates[ns] 115 if !ok { 116 return nil 117 } 118 vv, ok := nsUpdates.m[key] 119 if !ok { 120 return nil 121 } 122 return vv 123 } 124 125 // Put adds a VersionedKV 126 func (batch *UpdateBatch) Put(ns string, key string, value []byte, version *version.Height) { 127 if value == nil { 128 panic("Nil value not allowed") 129 } 130 nsUpdates := batch.getOrCreateNsUpdates(ns) 131 nsUpdates.m[key] = &VersionedValue{value, version} 132 } 133 134 // Delete deletes a Key and associated value 135 func (batch *UpdateBatch) Delete(ns string, key string, version *version.Height) { 136 nsUpdates := batch.getOrCreateNsUpdates(ns) 137 nsUpdates.m[key] = &VersionedValue{nil, version} 138 } 139 140 // Exists checks whether the given key exists in the batch 141 func (batch *UpdateBatch) Exists(ns string, key string) bool { 142 nsUpdates, ok := batch.updates[ns] 143 if !ok { 144 return false 145 } 146 _, ok = nsUpdates.m[key] 147 return ok 148 } 149 150 // GetUpdatedNamespaces returns the names of the namespaces that are updated 151 func (batch *UpdateBatch) GetUpdatedNamespaces() []string { 152 namespaces := make([]string, len(batch.updates)) 153 i := 0 154 for ns := range batch.updates { 155 namespaces[i] = ns 156 i++ 157 } 158 return namespaces 159 } 160 161 // GetUpdates returns all the updates for a namespace 162 func (batch *UpdateBatch) GetUpdates(ns string) map[string]*VersionedValue { 163 nsUpdates, ok := batch.updates[ns] 164 if !ok { 165 return nil 166 } 167 return nsUpdates.m 168 } 169 170 // GetRangeScanIterator returns an iterator that iterates over keys of a specific namespace in sorted order 171 // In other word this gives the same functionality over the contents in the `UpdateBatch` as 172 // `VersionedDB.GetStateRangeScanIterator()` method gives over the contents in the statedb 173 // This function can be used for querying the contents in the updateBatch before they are committed to the statedb. 174 // For instance, a validator implementation can used this to verify the validity of a range query of a transaction 175 // where the UpdateBatch represents the union of the modifications performed by the preceding valid transactions in the same block 176 // (Assuming Group commit approach where we commit all the updates caused by a block together). 177 func (batch *UpdateBatch) GetRangeScanIterator(ns string, startKey string, endKey string) ResultsIterator { 178 return newNsIterator(ns, startKey, endKey, batch) 179 } 180 181 func (batch *UpdateBatch) getOrCreateNsUpdates(ns string) *nsUpdates { 182 nsUpdates := batch.updates[ns] 183 if nsUpdates == nil { 184 nsUpdates = newNsUpdates() 185 batch.updates[ns] = nsUpdates 186 } 187 return nsUpdates 188 } 189 190 type nsIterator struct { 191 ns string 192 nsUpdates *nsUpdates 193 sortedKeys []string 194 nextIndex int 195 lastIndex int 196 } 197 198 func newNsIterator(ns string, startKey string, endKey string, batch *UpdateBatch) *nsIterator { 199 nsUpdates, ok := batch.updates[ns] 200 if !ok { 201 return &nsIterator{} 202 } 203 sortedKeys := util.GetSortedKeys(nsUpdates.m) 204 var nextIndex int 205 var lastIndex int 206 if startKey == "" { 207 nextIndex = 0 208 } else { 209 nextIndex = sort.SearchStrings(sortedKeys, startKey) 210 } 211 if endKey == "" { 212 lastIndex = len(sortedKeys) 213 } else { 214 lastIndex = sort.SearchStrings(sortedKeys, endKey) 215 } 216 return &nsIterator{ns, nsUpdates, sortedKeys, nextIndex, lastIndex} 217 } 218 219 // Next gives next key and versioned value. It returns a nil when exhausted 220 func (itr *nsIterator) Next() (QueryResult, error) { 221 if itr.nextIndex >= itr.lastIndex { 222 return nil, nil 223 } 224 key := itr.sortedKeys[itr.nextIndex] 225 vv := itr.nsUpdates.m[key] 226 itr.nextIndex++ 227 return &VersionedKV{CompositeKey{itr.ns, key}, VersionedValue{vv.Value, vv.Version}}, nil 228 } 229 230 // Close implements the method from QueryResult interface 231 func (itr *nsIterator) Close() { 232 // do nothing 233 } 234 235 //****************** 236 type TransferAmount struct { 237 balanceType string `json:"balanceType"` 238 amount *big.Int `json:"amount"` 239 } 240 241 type transferUpdates struct { 242 balanceUpdate map[string]*big.Int 243 version *version.Height 244 counter uint64 245 ink *big.Int 246 m map[string]*VersionedValue 247 } 248 type TransferBatch struct { 249 Updates map[string]*transferUpdates 250 } 251 252 func newTransferUpdates() *transferUpdates { 253 return &transferUpdates{make(map[string]*big.Int), nil, 0, nil, make(map[string]*VersionedValue)} 254 } 255 256 func NewTransferBatch() *TransferBatch { 257 return &TransferBatch{make(map[string]*transferUpdates)} 258 } 259 260 func (batch *TransferBatch) Put(from string, to string, balanceType string, amount []byte, version *version.Height) { 261 if amount == nil { 262 return 263 } 264 fromUpdates := batch.getOrCreateTransferUpdates(from) 265 fromBalance, ok := fromUpdates.balanceUpdate[balanceType] 266 if !ok { 267 fromBalance = big.NewInt(0) 268 fromUpdates.balanceUpdate[balanceType] = fromBalance 269 } 270 amountInt := new(big.Int).SetBytes(amount) 271 fromBalance = fromBalance.Sub(fromBalance, amountInt) 272 transAmount := &TransferAmount{balanceType: balanceType, amount: amountInt} 273 transAmountBytes, _ := json.Marshal(transAmount) 274 fromUpdates.m[to] = &VersionedValue{transAmountBytes, version} 275 toUpdates := batch.getOrCreateTransferUpdates(to) 276 toBalance, ok := toUpdates.balanceUpdate[balanceType] 277 if !ok { 278 toBalance = big.NewInt(0) 279 toUpdates.balanceUpdate[balanceType] = toBalance 280 } 281 282 toBalance = toBalance.Add(toBalance, new(big.Int).SetBytes(amount)) 283 if fromUpdates.version == nil || (fromUpdates.version != nil && fromUpdates.version.Compare(version) < 0) { 284 fromUpdates.version = version 285 } 286 if toUpdates.version == nil || (toUpdates.version != nil && toUpdates.version.Compare(version) < 0) { 287 toUpdates.version = version 288 } 289 } 290 291 func (batch *TransferBatch) getOrCreateTransferUpdates(from string) *transferUpdates { 292 transferUpdates, ok := batch.Updates[from] 293 if !ok { 294 transferUpdates = newTransferUpdates() 295 batch.Updates[from] = transferUpdates 296 } 297 return transferUpdates 298 } 299 300 func (batch *TransferBatch) UpdateSender(from string, counter uint64, ink *big.Int, version *version.Height) { 301 transferUpdates, ok := batch.Updates[from] 302 if !ok { 303 transferUpdates = newTransferUpdates() 304 batch.Updates[from] = transferUpdates 305 } 306 transferUpdates.version = version 307 transferUpdates.counter = counter + 1 308 if transferUpdates.ink == nil { 309 transferUpdates.ink = ink 310 } else { 311 transferUpdates.ink = ink.Add(transferUpdates.ink, ink) 312 } 313 } 314 func (batch *TransferBatch) GetSenderCounter(from string) (uint64, bool) { 315 transferUpdates, ok := batch.Updates[from] 316 if !ok { 317 return 0, ok 318 } 319 return transferUpdates.counter, ok 320 } 321 322 func (batch *TransferBatch) GetSenderInk(from string) (*big.Int, bool) { 323 transferUpdates, ok := batch.Updates[from] 324 if !ok { 325 return nil, ok 326 } 327 return transferUpdates.ink, ok 328 } 329 func (batch *TransferBatch) ExistsFrom(from string) bool { 330 _, ok := batch.Updates[from] 331 return ok 332 } 333 func (batch *TransferBatch) ExistsTransfer(from string, to string) bool { 334 transferUpdates, ok := batch.Updates[from] 335 if !ok { 336 return false 337 } 338 _, ok = transferUpdates.m[to] 339 return ok 340 } 341 func (batch *TransferBatch) GetBalanceUpdate(from string, balanceType string) *big.Int { 342 transferUpdates, ok := batch.Updates[from] 343 if !ok { 344 return nil 345 } 346 balance, ok := transferUpdates.balanceUpdate[balanceType] 347 if !ok { 348 return nil 349 } 350 return balance 351 } 352 func (batch *TransferBatch) GetAllBalanceUpdates(from string) map[string]*big.Int { 353 transferUpdates, ok := batch.Updates[from] 354 if !ok { 355 return nil 356 } 357 return transferUpdates.balanceUpdate 358 } 359 func (batch *TransferBatch) GetBalanceVersion(from string) *version.Height { 360 transferUpdates, ok := batch.Updates[from] 361 if !ok { 362 return nil 363 } 364 return transferUpdates.version 365 } 366 func (batch *TransferBatch) Get(from string, to string) *VersionedValue { 367 transferUpdates, ok := batch.Updates[from] 368 if !ok { 369 return nil 370 } 371 vv, ok := transferUpdates.m[to] 372 if !ok { 373 return nil 374 } 375 return vv 376 }