github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/execution/state/events.go (about) 1 package state 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 8 "github.com/hyperledger/burrow/encoding" 9 "github.com/hyperledger/burrow/execution/exec" 10 "github.com/hyperledger/burrow/storage" 11 ) 12 13 func (ws *writeState) AddBlock(be *exec.BlockExecution) error { 14 // If there are no transactions, do not store anything. This reduces the amount of data we store and 15 // prevents the iavl tree from changing, which means the AppHash does not change. If the AppHash changes then 16 // Tendermint will always produce another block. If we change the AppHash on empty blocks then we will continue 17 // creating empty blocks even if we have been configure to not do so. 18 // TODO: we would prefer not to do this and instead store sequential monotonic blocks, once this: 19 // https://github.com/tendermint/tendermint/issues/1909 is resolved we should be able to suppress empty blocks 20 // even when the AppHash changes 21 if len(be.TxExecutions) == 0 { 22 return nil 23 } 24 buf := new(bytes.Buffer) 25 var offset int 26 for _, ev := range be.StreamEvents() { 27 switch { 28 case ev.BeginTx != nil: 29 val := &exec.TxExecutionKey{Height: be.Height, Offset: uint64(offset)} 30 bs, err := encoding.Encode(val) 31 if err != nil { 32 return err 33 } 34 // Set reference to TxExecution 35 err = ws.plain.Set(keys.TxHash.Key(ev.BeginTx.TxHeader.TxHash), bs) 36 if err != nil { 37 return err 38 } 39 } 40 41 n, err := encoding.WriteMessage(buf, ev) 42 if err != nil { 43 return err 44 } 45 offset += n 46 } 47 48 return ws.forest.Write(keys.Event.Prefix(), func(tree *storage.RWTree) error { 49 key := keys.Event.KeyNoPrefix(be.Height) 50 tree.Set(key, buf.Bytes()) 51 return nil 52 }) 53 } 54 55 // Iterate SteamEvents over the closed interval [startHeight, endHeight] - i.e. startHeight and endHeight inclusive 56 func (s *ImmutableState) IterateStreamEvents(startHeight, endHeight *uint64, sortOrder storage.SortOrder, 57 consumer func(*exec.StreamEvent) error) error { 58 tree, err := s.Forest.Reader(keys.Event.Prefix()) 59 if err != nil { 60 return err 61 } 62 var startKey, endKey []byte 63 if startHeight != nil { 64 startKey = keys.Event.KeyNoPrefix(*startHeight) 65 } 66 if endHeight != nil { 67 // Convert to inclusive end bounds since this generally makes more sense for block height 68 endKey = keys.Event.KeyNoPrefix(*endHeight + 1) 69 } 70 return tree.Iterate(startKey, endKey, sortOrder == storage.AscendingSort, func(_, value []byte) error { 71 buf := bytes.NewBuffer(value) 72 73 for { 74 ev := new(exec.StreamEvent) 75 _, err := encoding.ReadMessage(buf, ev) 76 if err != nil { 77 if err == io.EOF { 78 return nil 79 } 80 return err 81 } 82 83 err = consumer(ev) 84 if err != nil { 85 return err 86 } 87 } 88 }) 89 } 90 91 func (s *ImmutableState) TxsAtHeight(height uint64) ([]*exec.TxExecution, error) { 92 const errHeader = "TxAtHeight():" 93 var stack exec.TxStack 94 var txExecutions []*exec.TxExecution 95 err := s.IterateStreamEvents(&height, &height, storage.AscendingSort, func(ev *exec.StreamEvent) error { 96 // Keep trying to consume TxExecutions at from events at this height 97 txe, err := stack.Consume(ev) 98 if err != nil { 99 return err 100 } 101 if txe != nil { 102 txExecutions = append(txExecutions, txe) 103 } 104 return nil 105 }) 106 if err != nil && err != io.EOF { 107 return nil, fmt.Errorf("%s %v", errHeader, err) 108 } 109 return txExecutions, nil 110 } 111 112 func (s *ReadState) TxByHash(txHash []byte) (*exec.TxExecution, error) { 113 const errHeader = "TxByHash():" 114 bs, err := s.Plain.Get(keys.TxHash.Key(txHash)) 115 if err != nil { 116 return nil, err 117 } 118 if len(bs) == 0 { 119 return nil, nil 120 } 121 122 key := new(exec.TxExecutionKey) 123 err = encoding.Decode(bs, key) 124 if err != nil { 125 return nil, err 126 } 127 128 blockTree, err := s.Forest.Reader(keys.Event.Prefix()) 129 if err != nil { 130 return nil, err 131 } 132 133 bs, err = blockTree.Get(keys.Event.KeyNoPrefix(key.Height)) 134 if err != nil { 135 return nil, err 136 } else if len(bs) == 0 { 137 return nil, fmt.Errorf("%s could not retrieve transaction with TxHash %X despite finding reference", 138 errHeader, txHash) 139 } 140 141 buf := bytes.NewBuffer(bs[key.Offset:]) 142 var stack exec.TxStack 143 144 for { 145 ev := new(exec.StreamEvent) 146 _, err := encoding.ReadMessage(buf, ev) 147 if err != nil { 148 return nil, err 149 } 150 151 txe, err := stack.Consume(ev) 152 if err != nil { 153 return nil, fmt.Errorf("%s: %v", errHeader, err) 154 } 155 if txe != nil { 156 return txe, nil 157 } 158 } 159 } 160 161 // Get the last block height we stored in state 162 func (s *ImmutableState) LastStoredHeight() (uint64, error) { 163 var height uint64 164 err := s.IterateStreamEvents(nil, nil, storage.DescendingSort, 165 func(event *exec.StreamEvent) error { 166 if event.EndBlock != nil { 167 height = event.EndBlock.Height 168 return io.EOF 169 } 170 return nil 171 }) 172 if err != nil && err != io.EOF { 173 return 0, fmt.Errorf("LastStoredHeight: %w", err) 174 } 175 return height, nil 176 }