github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/core/rawdb/tx3_local_database_util.go (about) 1 package rawdb 2 3 import ( 4 "bytes" 5 "fmt" 6 7 ntcTypes "github.com/neatio-net/neatio/chain/consensus/neatcon/types" 8 "github.com/neatio-net/neatio/chain/core/types" 9 "github.com/neatio-net/neatio/chain/trie" 10 neatAbi "github.com/neatio-net/neatio/neatabi/abi" 11 "github.com/neatio-net/neatio/neatdb" 12 "github.com/neatio-net/neatio/params" 13 "github.com/neatio-net/neatio/utilities/common" 14 "github.com/neatio-net/neatio/utilities/rlp" 15 ) 16 17 var ( 18 tx3Prefix = []byte("t") // tx3Prefix + chainId + txHash -> tx3 19 tx3LookupPrefix = []byte("k") // tx3LookupPrefix + chainId + txHash -> tx3 lookup metadata 20 tx3ProofPrefix = []byte("p") // tx3ProofPrefix + chainId + height -> proof data 21 ) 22 23 // TX3LookupEntry is a positional metadata to help looking up the tx3 proof content given only its chainId and hash. 24 type TX3LookupEntry struct { 25 BlockIndex uint64 26 TxIndex uint64 27 } 28 29 func GetTX3(db neatdb.Reader, chainId string, txHash common.Hash) *types.Transaction { 30 key := append(tx3Prefix, append([]byte(chainId), txHash.Bytes()...)...) 31 bs, err := db.Get(key) 32 if len(bs) == 0 || err != nil { 33 return nil 34 } 35 36 tx, err := decodeTx(bs) 37 if err != nil { 38 return nil 39 } 40 41 return tx 42 } 43 44 func GetTX3ProofData(db neatdb.Reader, chainId string, txHash common.Hash) *types.TX3ProofData { 45 // Retrieve the lookup metadata 46 hash, blockNumber, txIndex := GetTX3LookupEntry(db, chainId, txHash) 47 if hash == (common.Hash{}) { 48 return nil 49 } 50 51 encNum := encodeBlockNumber(blockNumber) 52 key := append(tx3ProofPrefix, append([]byte(chainId), encNum...)...) 53 bs, err := db.Get(key) 54 if len(bs) == 0 || err != nil { 55 return nil 56 } 57 58 var proofData types.TX3ProofData 59 err = rlp.DecodeBytes(bs, &proofData) 60 if err != nil { 61 return nil 62 } 63 64 var i int 65 for i = 0; i < len(proofData.TxIndexs); i++ { 66 if uint64(proofData.TxIndexs[i]) == txIndex { 67 break 68 } 69 } 70 if i >= len(proofData.TxIndexs) { // can't find the txIndex 71 return nil 72 } 73 74 ret := types.TX3ProofData{ 75 Header: proofData.Header, 76 TxIndexs: make([]uint, 1), 77 TxProofs: make([]*types.BSKeyValueSet, 1), 78 } 79 ret.TxIndexs[0] = proofData.TxIndexs[i] 80 ret.TxProofs[0] = proofData.TxProofs[i] 81 82 return &ret 83 } 84 85 func GetTX3LookupEntry(db neatdb.Reader, chainId string, txHash common.Hash) (common.Hash, uint64, uint64) { 86 // Load the positional metadata from disk and bail if it fails 87 key := append(tx3LookupPrefix, append([]byte(chainId), txHash.Bytes()...)...) 88 bs, err := db.Get(key) 89 if len(bs) == 0 || err != nil { 90 return common.Hash{}, 0, 0 91 } 92 93 // Parse and return the contents of the lookup entry 94 var entry TX3LookupEntry 95 if err := rlp.DecodeBytes(bs, &entry); err != nil { 96 return common.Hash{}, 0, 0 97 } 98 return txHash, entry.BlockIndex, entry.TxIndex 99 } 100 101 func GetAllTX3ProofData(db neatdb.Database) []*types.TX3ProofData { 102 var ret []*types.TX3ProofData 103 iter := db.NewIteratorWithPrefix(tx3ProofPrefix) 104 for iter.Next() { 105 key := iter.Key() 106 value := iter.Value() 107 108 if !bytes.HasPrefix(key, tx3ProofPrefix) { 109 break 110 } 111 112 var proofData *types.TX3ProofData 113 err := rlp.DecodeBytes(value, proofData) 114 if err != nil { 115 continue 116 } 117 ret = append(ret, proofData) 118 } 119 120 return ret 121 } 122 123 // WriteTX3ProofData serializes TX3ProofData into the database. 124 func WriteTX3ProofData(db neatdb.Database, proofData *types.TX3ProofData) error { 125 header := proofData.Header 126 ncExtra, err := ntcTypes.ExtractNeatConExtra(header) 127 if err != nil { 128 return err 129 } 130 131 chainId := ncExtra.ChainID 132 if chainId == "" || chainId == params.MainnetChainConfig.NeatChainId || chainId == params.TestnetChainConfig.NeatChainId { 133 return fmt.Errorf("invalid side chain id: %s", chainId) 134 } 135 136 num := header.Number.Uint64() 137 encNum := encodeBlockNumber(num) 138 key1 := append(tx3ProofPrefix, append([]byte(chainId), encNum...)...) 139 bs, err := db.Get(key1) 140 if len(bs) == 0 || err != nil { // not exists yet. 141 bss, _ := rlp.EncodeToBytes(proofData) 142 if err := db.Put(key1, bss); err != nil { 143 return err 144 } 145 146 for i, txIndex := range proofData.TxIndexs { 147 if err := WriteTX3(db, chainId, header, txIndex, proofData.TxProofs[i]); err != nil { 148 return err 149 } 150 } 151 } else { // merge to the existing one. 152 var existProofData types.TX3ProofData 153 err = rlp.DecodeBytes(bs, &existProofData) 154 if err != nil { 155 return err 156 } 157 158 var update bool 159 for i, txIndex := range proofData.TxIndexs { 160 if !hasTxIndex(&existProofData, txIndex) { 161 if err := WriteTX3(db, chainId, header, txIndex, proofData.TxProofs[i]); err != nil { 162 return err 163 } 164 165 existProofData.TxIndexs = append(existProofData.TxIndexs, txIndex) 166 existProofData.TxProofs = append(existProofData.TxProofs, proofData.TxProofs[i]) 167 update = true 168 } 169 } 170 171 if update { 172 bss, _ := rlp.EncodeToBytes(existProofData) 173 if err := db.Put(key1, bss); err != nil { 174 return err 175 } 176 } 177 } 178 179 return nil 180 } 181 182 func hasTxIndex(proofData *types.TX3ProofData, target uint) bool { 183 for _, txIndex := range proofData.TxIndexs { 184 if txIndex == target { 185 return true 186 } 187 } 188 return false 189 } 190 191 func WriteTX3(db neatdb.Writer, chainId string, header *types.Header, txIndex uint, txProofData *types.BSKeyValueSet) error { 192 keybuf := new(bytes.Buffer) 193 rlp.Encode(keybuf, txIndex) 194 val, _, err := trie.VerifyProof(header.TxHash, keybuf.Bytes(), txProofData) 195 if err != nil { 196 return err 197 } 198 199 var tx types.Transaction 200 err = rlp.DecodeBytes(val, &tx) 201 if err != nil { 202 return err 203 } 204 205 if neatAbi.IsNeatChainContractAddr(tx.To()) { 206 data := tx.Data() 207 function, err := neatAbi.FunctionTypeFromId(data[:4]) 208 if err != nil { 209 return err 210 } 211 212 if function == neatAbi.WithdrawFromSideChain { 213 txHash := tx.Hash() 214 key1 := append(tx3Prefix, append([]byte(chainId), txHash.Bytes()...)...) 215 bs, _ := rlp.EncodeToBytes(&tx) 216 if err = db.Put(key1, bs); err != nil { 217 return err 218 } 219 220 entry := TX3LookupEntry{ 221 BlockIndex: header.Number.Uint64(), 222 TxIndex: uint64(txIndex), 223 } 224 data, _ := rlp.EncodeToBytes(entry) 225 key2 := append(tx3LookupPrefix, append([]byte(chainId), txHash.Bytes()...)...) 226 if err := db.Put(key2, data); err != nil { 227 return err 228 } 229 } 230 } 231 232 return nil 233 } 234 235 func DeleteTX3(db neatdb.Database, chainId string, txHash common.Hash) { 236 // Retrieve the lookup metadata 237 hash, blockNumber, txIndex := GetTX3LookupEntry(db, chainId, txHash) 238 if hash == (common.Hash{}) { 239 return 240 } 241 242 // delete the tx3 itself 243 key1 := append(tx3Prefix, append([]byte(chainId), txHash.Bytes()...)...) 244 db.Delete(key1) 245 246 // delete the tx3 lookup metadata 247 key2 := append(tx3LookupPrefix, append([]byte(chainId), txHash.Bytes()...)...) 248 db.Delete(key2) 249 250 encNum := encodeBlockNumber(blockNumber) 251 key3 := append(tx3ProofPrefix, append([]byte(chainId), encNum...)...) 252 bs, err := db.Get(key3) 253 if len(bs) == 0 || err != nil { 254 return 255 } 256 257 var proofData types.TX3ProofData 258 err = rlp.DecodeBytes(bs, &proofData) 259 if err != nil { 260 return 261 } 262 263 var i int 264 for i = 0; i < len(proofData.TxIndexs); i++ { 265 if uint64(proofData.TxIndexs[i]) == txIndex { 266 break 267 } 268 } 269 if i >= len(proofData.TxIndexs) { // can't find the txIndex 270 return 271 } 272 273 proofData.TxIndexs = append(proofData.TxIndexs[:i], proofData.TxIndexs[i+1:]...) 274 proofData.TxProofs = append(proofData.TxProofs[:i], proofData.TxProofs[i+1:]...) 275 if len(proofData.TxIndexs) == 0 { 276 // delete the whole proof data 277 db.Delete(key3) 278 } else { 279 // update the proof data 280 bs, _ := rlp.EncodeToBytes(proofData) 281 db.Put(key3, bs) 282 } 283 } 284 285 func decodeTx(txBytes []byte) (*types.Transaction, error) { 286 287 tx := new(types.Transaction) 288 rlpStream := rlp.NewStream(bytes.NewBuffer(txBytes), 0) 289 if err := tx.DecodeRLP(rlpStream); err != nil { 290 return nil, err 291 } 292 return tx, nil 293 }