github.com/koko1123/flow-go-1@v0.29.6/ledger/complete/wal/encoding.go (about) 1 package wal 2 3 import ( 4 "fmt" 5 6 "github.com/koko1123/flow-go-1/ledger" 7 "github.com/koko1123/flow-go-1/ledger/common/utils" 8 ) 9 10 type WALOperation uint8 11 12 const WALUpdate WALOperation = 1 13 const WALDelete WALOperation = 2 14 15 /* 16 The LedgerWAL update record uses two operations so far - an update which must include all keys and values, and deletion 17 which only needs a root tree state commitment. 18 Updates need to be atomic, hence we prepare binary representation of whole changeset. 19 Since keys, values and state commitments date types are variable length, we have to store it as well. 20 If OP = WALDelete, record has: 21 22 1 byte Operation Type | 2 bytes Big Endian uint16 length of state commitment | state commitment data 23 24 If OP = WALUpdate, record has: 25 26 1 byte Operation Type | 2 bytes version | 1 byte TypeTrieUpdate | 2 bytes Big Endian uint16 length of state commitment | state commitment data | 27 4 bytes Big Endian uint32 - total number of key/value pairs | 2 bytes Big Endian uint16 - length of key (keys are the same length) 28 29 and for every pair after 30 bytes for key | 4 bytes Big Endian uint32 - length of value | value bytes 31 32 The code here is deliberately simple, for performance. 33 34 */ 35 36 func EncodeUpdate(update *ledger.TrieUpdate) []byte { 37 encUpdate := ledger.EncodeTrieUpdate(update) 38 buf := make([]byte, len(encUpdate)+1) 39 // set WAL type 40 buf[0] = byte(WALUpdate) 41 // TODO use 2 bytes for encoding length 42 // the rest is encoded update 43 copy(buf[1:], encUpdate) 44 return buf 45 } 46 47 func EncodeDelete(rootHash ledger.RootHash) []byte { 48 buf := make([]byte, 0, 1+2+len(rootHash)) 49 buf = append(buf, byte(WALDelete)) 50 buf = utils.AppendShortData(buf, rootHash[:]) 51 return buf 52 } 53 54 func Decode(data []byte) (operation WALOperation, rootHash ledger.RootHash, update *ledger.TrieUpdate, err error) { 55 if len(data) < 4 { // 1 byte op + 2 size + actual data = 4 minimum 56 err = fmt.Errorf("data corrupted, too short to represent operation - hexencoded data: %x", data) 57 return 58 } 59 60 operation = WALOperation(data[0]) 61 switch operation { 62 case WALUpdate: 63 update, err = ledger.DecodeTrieUpdate(data[1:]) 64 return 65 case WALDelete: 66 var rootHashBytes []byte 67 rootHashBytes, _, err = utils.ReadShortData(data[1:]) 68 if err != nil { 69 err = fmt.Errorf("cannot read state commitment: %w", err) 70 return 71 } 72 rootHash, err = ledger.ToRootHash(rootHashBytes) 73 if err != nil { 74 err = fmt.Errorf("invalid root hash: %w", err) 75 return 76 } 77 return 78 default: 79 err = fmt.Errorf("unknown operation type, given: %x", operation) 80 return 81 } 82 }