github.com/Tri-stone/burrow@v0.25.0/execution/state/events_test.go (about) 1 package state 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/hyperledger/burrow/binary" 8 "github.com/hyperledger/burrow/crypto" 9 "github.com/hyperledger/burrow/crypto/sha3" 10 "github.com/hyperledger/burrow/execution/exec" 11 "github.com/stretchr/testify/require" 12 "github.com/tendermint/tendermint/libs/db" 13 ) 14 15 func TestWriteState_AddBlock(t *testing.T) { 16 s := NewState(db.NewMemDB()) 17 height := uint64(100) 18 numTxs := uint64(5) 19 events := uint64(10) 20 block := mkBlock(height, numTxs, events) 21 _, _, err := s.Update(func(ws Updatable) error { 22 return ws.AddBlock(block) 23 }) 24 require.NoError(t, err) 25 26 txIndex := uint64(0) 27 eventIndex := uint64(0) 28 err = s.IterateStreamEvents(&exec.StreamKey{Height: height}, &exec.StreamKey{Height: height + 1}, 29 func(ev *exec.StreamEvent) error { 30 switch { 31 case ev.BeginTx != nil: 32 eventIndex = 0 33 case ev.Event != nil: 34 require.Equal(t, mkEvent(height, txIndex, eventIndex).Header.TxHash.String(), 35 ev.Event.Header.TxHash.String(), "event TxHash mismatch at tx #%d event #%d", 36 txIndex, eventIndex) 37 eventIndex++ 38 case ev.EndTx != nil: 39 txIndex++ 40 } 41 return nil 42 }) 43 require.NoError(t, err) 44 require.Equal(t, numTxs, txIndex, "should have observed all txs") 45 // non-increasing events 46 _, _, err = s.Update(func(ws Updatable) error { 47 return nil 48 }) 49 require.NoError(t, err) 50 51 txExecutions, err := s.TxsAtHeight(height) 52 require.NoError(t, err) 53 require.NotNil(t, txExecutions) 54 require.Equal(t, numTxs, uint64(len(txExecutions))) 55 } 56 57 func TestNestedTxs(t *testing.T) { 58 s := NewState(db.NewMemDB()) 59 height := uint64(2) 60 numTxs := uint64(4) 61 events := uint64(2) 62 nesting := uint64(3) 63 block := mkBlock(height, numTxs, events) 64 txes := block.TxExecutions 65 // Deeply nest transactions inside block 66 for i := uint64(0); i < nesting; i++ { 67 var next []*exec.TxExecution 68 for _, txe := range txes { 69 next = append(next, nestTxs(txe, height, events+i, numTxs+i)...) 70 } 71 txes = next 72 } 73 _, _, err := s.Update(func(ws Updatable) error { 74 return ws.AddBlock(block) 75 }) 76 require.NoError(t, err) 77 txes, err = s.TxsAtHeight(height) 78 require.NoError(t, err) 79 txsCount := deepCountTxs(block.TxExecutions) 80 require.Equal(t, txsCount, deepCountTxs(txes)) 81 // There is a geometric-arithmetic sum here... but empiricism FTW 82 require.Equal(t, 580, txsCount) 83 } 84 85 func TestReadState_TxByHash(t *testing.T) { 86 s := NewState(db.NewMemDB()) 87 maxHeight := uint64(3) 88 numTxs := uint64(4) 89 events := uint64(2) 90 for height := uint64(0); height < maxHeight; height++ { 91 block := mkBlock(height, numTxs, events) 92 _, _, err := s.Update(func(ws Updatable) error { 93 return ws.AddBlock(block) 94 }) 95 require.NoError(t, err) 96 } 97 98 hashSet := make(map[string]bool) 99 for height := uint64(0); height < maxHeight; height++ { 100 for txIndex := uint64(0); txIndex < numTxs; txIndex++ { 101 // Find this tx 102 tx := mkTx(height, txIndex, events) 103 txHash := tx.TxHash.String() 104 // Check we have no duplicates (indicates problem with how we are generating hashes for these tests 105 require.False(t, hashSet[txHash], "should be no duplicate tx hashes") 106 hashSet[txHash] = true 107 // Try and pull the Tx by its hash 108 txOut, err := s.TxByHash(tx.TxHash) 109 require.NoError(t, err) 110 require.NotNil(t, txOut, "should retrieve non-nil transaction by TxHash %v", tx.TxHash) 111 // Make sure we get the same tx 112 require.Equal(t, txHash, txOut.TxHash.String(), "TxHash does not match as string") 113 require.Equal(t, *tx, *txOut) 114 } 115 } 116 } 117 118 func deepCountTxs(txes []*exec.TxExecution) int { 119 sum := len(txes) 120 for _, txe := range txes { 121 sum += deepCountTxs(txe.TxExecutions) 122 } 123 return sum 124 } 125 126 func nestTxs(txe *exec.TxExecution, height, events, numTxs uint64) []*exec.TxExecution { 127 txes := make([]*exec.TxExecution, numTxs) 128 for i := uint64(0); i < numTxs; i++ { 129 txes[i] = mkTx(height, i, events) 130 txe.TxExecutions = append(txe.TxExecutions, txes[i]) 131 } 132 return txes 133 } 134 135 func mkBlock(height, numTxs, events uint64) *exec.BlockExecution { 136 be := &exec.BlockExecution{ 137 Height: height, 138 } 139 for ti := uint64(0); ti < numTxs; ti++ { 140 txe := mkTx(height, ti, events) 141 be.TxExecutions = append(be.TxExecutions, txe) 142 } 143 return be 144 } 145 146 func mkTx(height, txIndex, events uint64) *exec.TxExecution { 147 hash := make([]byte, 32) 148 binary.PutUint64BE(hash[:8], height) 149 binary.PutUint64BE(hash[8:16], txIndex) 150 binary.PutUint64BE(hash[16:24], events) 151 txe := &exec.TxExecution{ 152 TxHeader: &exec.TxHeader{ 153 TxHash: hash, 154 Height: height, 155 Index: txIndex, 156 }, 157 } 158 for e := uint64(0); e < events; e++ { 159 txe.Events = append(txe.Events, mkEvent(height, txIndex, e)) 160 } 161 return txe 162 } 163 164 func mkEvent(height, tx, index uint64) *exec.Event { 165 return &exec.Event{ 166 Header: &exec.Header{ 167 Height: height, 168 Index: index, 169 TxHash: sha3.Sha3([]byte(fmt.Sprintf("txhash%v%v%v", height, tx, index))), 170 EventID: fmt.Sprintf("eventID: %v%v%v", height, tx, index), 171 }, 172 Log: &exec.LogEvent{ 173 Address: crypto.Address{byte(height), byte(index)}, 174 Topics: []binary.Word256{{1, 2, 3}}, 175 }, 176 } 177 }