Official Go implementation of the Bytom protocol
Revision | 5566834e066663e41c4b7ad2d547a72fcb989547 (tree) |
---|---|
Zeit | 2019-08-13 16:07:03 |
Autor | Yahtoo Ma <yahtoo.ma@gmai...> |
Commiter | Yahtoo Ma |
restore Tx back to Tx pool when chain is reorganized
@@ -102,6 +102,7 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error { | ||
102 | 102 | attachNodes, detachNodes := c.calcReorganizeNodes(node) |
103 | 103 | utxoView := state.NewUtxoViewpoint() |
104 | 104 | |
105 | + txsToRestore := map[bc.Hash]*types.Tx{} | |
105 | 106 | for _, detachNode := range detachNodes { |
106 | 107 | b, err := c.store.GetBlock(&detachNode.Hash) |
107 | 108 | if err != nil { |
@@ -120,9 +121,13 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error { | ||
120 | 121 | return err |
121 | 122 | } |
122 | 123 | |
124 | + for _, tx := range b.Transactions { | |
125 | + txsToRestore[tx.ID] = tx | |
126 | + } | |
123 | 127 | log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain") |
124 | 128 | } |
125 | 129 | |
130 | + txsToRemove := map[bc.Hash]*types.Tx{} | |
126 | 131 | for _, attachNode := range attachNodes { |
127 | 132 | b, err := c.store.GetBlock(&attachNode.Hash) |
128 | 133 | if err != nil { |
@@ -141,10 +146,39 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error { | ||
141 | 146 | return err |
142 | 147 | } |
143 | 148 | |
149 | + for _, tx := range b.Transactions { | |
150 | + if _, ok := txsToRestore[tx.ID]; !ok { | |
151 | + txsToRemove[tx.ID] = tx | |
152 | + } else { | |
153 | + delete(txsToRestore, tx.ID) | |
154 | + } | |
155 | + } | |
156 | + | |
144 | 157 | log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain") |
145 | 158 | } |
146 | 159 | |
147 | - return c.setState(node, utxoView) | |
160 | + if err := c.setState(node, utxoView); err != nil { | |
161 | + return err | |
162 | + } | |
163 | + | |
164 | + for txHash := range txsToRemove { | |
165 | + c.txPool.RemoveTransaction(&txHash) | |
166 | + } | |
167 | + | |
168 | + for _, tx := range txsToRestore { | |
169 | + // the number of restored Tx should be very small or most of time ZERO | |
170 | + // Error returned from validation is ignored, tx could still be lost if validation fails. | |
171 | + // TODO: adjust tx timestamp so that it won't starve in pool. | |
172 | + if _, err := c.ValidateTx(tx); err != nil { | |
173 | + log.WithFields(log.Fields{"module": logModule, "tx_id": tx.Tx.ID.String(), "error": err}).Info("restore tx fail") | |
174 | + } | |
175 | + } | |
176 | + | |
177 | + if len(txsToRestore) > 0 { | |
178 | + log.WithFields(log.Fields{"module": logModule, "num": len(txsToRestore)}).Debug("restore txs back to pool") | |
179 | + } | |
180 | + | |
181 | + return nil | |
148 | 182 | } |
149 | 183 | |
150 | 184 | // SaveBlock will validate and save block into storage |