github.com/onflow/flow-go@v0.33.17/fvm/storage/state/spock_state.go (about) 1 package state 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 7 "github.com/onflow/flow-go/crypto/hash" 8 "github.com/onflow/flow-go/fvm/storage/snapshot" 9 "github.com/onflow/flow-go/model/flow" 10 ) 11 12 var ( 13 // Note: encoding the operation type as part of the spock hash 14 // prevents operation injection/substitution attacks. 15 getMarker = []byte("1") 16 setMarker = []byte("2") 17 dropChangesMarker = []byte("3") 18 mergeMarker = []byte("4") 19 ) 20 21 type spockState struct { 22 *storageState 23 24 spockSecretHasher hash.Hasher 25 26 // NOTE: spockState is no longer accessible once Finalize is called. We 27 // can't support access after Finalize since spockSecretHasher.SumHash is 28 // not idempotent. Repeated calls to SumHash (without modifying the input) 29 // may return different hashes. 30 finalizedSpockSecret []byte 31 } 32 33 func newSpockState(base snapshot.StorageSnapshot) *spockState { 34 return &spockState{ 35 storageState: newStorageState(base), 36 spockSecretHasher: hash.NewSHA3_256(), 37 } 38 } 39 40 func (state *spockState) NewChild() *spockState { 41 return &spockState{ 42 storageState: state.storageState.NewChild(), 43 spockSecretHasher: hash.NewSHA3_256(), 44 } 45 } 46 47 func (state *spockState) Finalize() *snapshot.ExecutionSnapshot { 48 if state.finalizedSpockSecret == nil { 49 state.finalizedSpockSecret = state.spockSecretHasher.SumHash() 50 } 51 52 snapshot := state.storageState.Finalize() 53 snapshot.SpockSecret = state.finalizedSpockSecret 54 return snapshot 55 } 56 57 func (state *spockState) Merge(snapshot *snapshot.ExecutionSnapshot) error { 58 if state.finalizedSpockSecret != nil { 59 return fmt.Errorf("cannot Merge on a finalized state") 60 } 61 62 _, err := state.spockSecretHasher.Write(mergeMarker) 63 if err != nil { 64 return fmt.Errorf("merge SPoCK failed: %w", err) 65 } 66 67 _, err = state.spockSecretHasher.Write(snapshot.SpockSecret) 68 if err != nil { 69 return fmt.Errorf("merge SPoCK failed: %w", err) 70 } 71 72 return state.storageState.Merge(snapshot) 73 } 74 75 func (state *spockState) Set( 76 id flow.RegisterID, 77 value flow.RegisterValue, 78 ) error { 79 if state.finalizedSpockSecret != nil { 80 return fmt.Errorf("cannot Set on a finalized state") 81 } 82 83 _, err := state.spockSecretHasher.Write(setMarker) 84 if err != nil { 85 return fmt.Errorf("set SPoCK failed: %w", err) 86 } 87 88 idBytes := id.Bytes() 89 90 // Note: encoding the register id / value length as part of spock hash 91 // to prevent string injection attacks. 92 err = binary.Write( 93 state.spockSecretHasher, 94 binary.LittleEndian, 95 int32(len(idBytes))) 96 if err != nil { 97 return fmt.Errorf("set SPoCK failed: %w", err) 98 } 99 100 _, err = state.spockSecretHasher.Write(idBytes) 101 if err != nil { 102 return fmt.Errorf("set SPoCK failed: %w", err) 103 } 104 105 err = binary.Write( 106 state.spockSecretHasher, 107 binary.LittleEndian, 108 int32(len(value))) 109 if err != nil { 110 return fmt.Errorf("set SPoCK failed: %w", err) 111 } 112 113 _, err = state.spockSecretHasher.Write(value) 114 if err != nil { 115 return fmt.Errorf("set SPoCK failed: %w", err) 116 } 117 118 return state.storageState.Set(id, value) 119 } 120 121 func (state *spockState) Get( 122 id flow.RegisterID, 123 ) ( 124 flow.RegisterValue, 125 error, 126 ) { 127 if state.finalizedSpockSecret != nil { 128 return nil, fmt.Errorf("cannot Get on a finalized state") 129 } 130 131 _, err := state.spockSecretHasher.Write(getMarker) 132 if err != nil { 133 return nil, fmt.Errorf("get SPoCK failed: %w", err) 134 } 135 136 idBytes := id.Bytes() 137 138 // Note: encoding the register id length as part of spock hash to prevent 139 // string injection attacks. 140 err = binary.Write( 141 state.spockSecretHasher, 142 binary.LittleEndian, 143 int32(len(idBytes))) 144 if err != nil { 145 return nil, fmt.Errorf("get SPoCK failed: %w", err) 146 } 147 148 _, err = state.spockSecretHasher.Write(idBytes) 149 if err != nil { 150 return nil, fmt.Errorf("get SPoCK failed: %w", err) 151 } 152 153 return state.storageState.Get(id) 154 } 155 156 func (state *spockState) DropChanges() error { 157 if state.finalizedSpockSecret != nil { 158 return fmt.Errorf("cannot DropChanges on a finalized state") 159 } 160 161 _, err := state.spockSecretHasher.Write(dropChangesMarker) 162 if err != nil { 163 return fmt.Errorf("drop changes SPoCK failed: %w", err) 164 } 165 166 return state.storageState.DropChanges() 167 } 168 169 func (state *spockState) readSetSize() int { 170 return state.storageState.readSetSize() 171 } 172 173 func (state *spockState) interimReadSet( 174 accumulator map[flow.RegisterID]struct{}, 175 ) { 176 state.storageState.interimReadSet(accumulator) 177 }