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  }