github.com/turingchain2020/turingchain@v1.1.21/blockchain/blocktable.go (about) 1 package blockchain 2 3 import ( 4 "fmt" 5 6 dbm "github.com/turingchain2020/turingchain/common/db" 7 "github.com/turingchain2020/turingchain/common/db/table" 8 "github.com/turingchain2020/turingchain/common/merkle" 9 "github.com/turingchain2020/turingchain/types" 10 ) 11 12 var ( 13 chainParaTxPrefix = []byte("CHAIN-paratx") 14 chainBodyPrefix = []byte("CHAIN-body") 15 chainHeaderPrefix = []byte("CHAIN-header") 16 chainReceiptPrefix = []byte("CHAIN-receipt") 17 ) 18 19 func calcHeightHashKey(height int64, hash []byte) []byte { 20 return append([]byte(fmt.Sprintf("%012d", height)), hash...) 21 } 22 func calcHeightParaKey(height int64) []byte { 23 return []byte(fmt.Sprintf("%012d", height)) 24 } 25 26 func calcHeightTitleKey(height int64, title string) []byte { 27 return append([]byte(fmt.Sprintf("%012d", height)), []byte(title)...) 28 } 29 30 /* 31 table body 32 data: block body 33 index: hash 34 */ 35 var bodyOpt = &table.Option{ 36 Prefix: "CHAIN-body", 37 Name: "body", 38 Primary: "heighthash", 39 Index: []string{"hash"}, 40 } 41 42 //NewBodyTable 新建表 43 func NewBodyTable(kvdb dbm.KV) *table.Table { 44 rowmeta := NewBodyRow() 45 table, err := table.NewTable(rowmeta, kvdb, bodyOpt) 46 if err != nil { 47 panic(err) 48 } 49 return table 50 } 51 52 //BodyRow table meta 结构 53 type BodyRow struct { 54 *types.BlockBody 55 } 56 57 //NewBodyRow 新建一个meta 结构 58 func NewBodyRow() *BodyRow { 59 return &BodyRow{BlockBody: &types.BlockBody{}} 60 } 61 62 //CreateRow 新建数据行 63 func (body *BodyRow) CreateRow() *table.Row { 64 return &table.Row{Data: &types.BlockBody{}} 65 } 66 67 //SetPayload 设置数据 68 func (body *BodyRow) SetPayload(data types.Message) error { 69 if blockbody, ok := data.(*types.BlockBody); ok { 70 body.BlockBody = blockbody 71 return nil 72 } 73 return types.ErrTypeAsset 74 } 75 76 //Get 获取索引对应的key值 77 func (body *BodyRow) Get(key string) ([]byte, error) { 78 if key == "heighthash" { 79 return calcHeightHashKey(body.Height, body.Hash), nil 80 } else if key == "hash" { 81 return body.Hash, nil 82 } 83 return nil, types.ErrNotFound 84 } 85 86 //saveBlockBodyTable 保存block body 87 func saveBlockBodyTable(db dbm.DB, body *types.BlockBody) ([]*types.KeyValue, error) { 88 kvdb := dbm.NewKVDB(db) 89 table := NewBodyTable(kvdb) 90 91 err := table.Replace(body) 92 if err != nil { 93 return nil, err 94 } 95 96 kvs, err := table.Save() 97 if err != nil { 98 return nil, err 99 } 100 return kvs, nil 101 } 102 103 //通过指定的index获取对应的blockbody 104 //通过高度获取:height+hash;indexName="",prefix=nil,primaryKey=calcHeightHashKey 105 //通过index获取:hash; indexName="hash",prefix=BodyRow.Get(indexName),primaryKey=nil 106 func getBodyByIndex(db dbm.DB, indexName string, prefix []byte, primaryKey []byte) (*types.BlockBody, error) { 107 kvdb := dbm.NewKVDB(db) 108 table := NewBodyTable(kvdb) 109 110 rows, err := table.ListIndex(indexName, prefix, primaryKey, 0, dbm.ListASC) 111 if err != nil { 112 return nil, err 113 } 114 if len(rows) != 1 { 115 panic("getBodyByIndex") 116 } 117 body, ok := rows[0].Data.(*types.BlockBody) 118 if !ok { 119 return nil, types.ErrDecode 120 } 121 return body, nil 122 } 123 124 //delBlockBodyTable 删除block Body 125 func delBlockBodyTable(db dbm.DB, height int64, hash []byte) ([]*types.KeyValue, error) { 126 kvdb := dbm.NewKVDB(db) 127 table := NewBodyTable(kvdb) 128 129 err := table.Del(calcHeightHashKey(height, hash)) 130 if err != nil { 131 return nil, err 132 } 133 134 kvs, err := table.Save() 135 if err != nil { 136 return nil, err 137 } 138 return kvs, nil 139 } 140 141 /* 142 table header 143 data: block header 144 primary:heighthash 145 index: hash 146 */ 147 var headerOpt = &table.Option{ 148 Prefix: "CHAIN-header", 149 Name: "header", 150 Primary: "heighthash", 151 Index: []string{"hash"}, 152 } 153 154 //HeaderRow table meta 结构 155 type HeaderRow struct { 156 *types.Header 157 } 158 159 //NewHeaderRow 新建一个meta 结构 160 func NewHeaderRow() *HeaderRow { 161 return &HeaderRow{Header: &types.Header{}} 162 } 163 164 //NewHeaderTable 新建表 165 func NewHeaderTable(kvdb dbm.KV) *table.Table { 166 rowmeta := NewHeaderRow() 167 table, err := table.NewTable(rowmeta, kvdb, headerOpt) 168 if err != nil { 169 panic(err) 170 } 171 return table 172 } 173 174 //CreateRow 新建数据行 175 func (header *HeaderRow) CreateRow() *table.Row { 176 return &table.Row{Data: &types.Header{}} 177 } 178 179 //SetPayload 设置数据 180 func (header *HeaderRow) SetPayload(data types.Message) error { 181 if blockheader, ok := data.(*types.Header); ok { 182 header.Header = blockheader 183 return nil 184 } 185 return types.ErrTypeAsset 186 } 187 188 //Get 获取索引对应的key值 189 func (header *HeaderRow) Get(key string) ([]byte, error) { 190 if key == "heighthash" { 191 return calcHeightHashKey(header.Height, header.Hash), nil 192 } else if key == "hash" { 193 return header.Hash, nil 194 } 195 return nil, types.ErrNotFound 196 } 197 198 //saveHeaderTable 保存block header 199 func saveHeaderTable(db dbm.DB, header *types.Header) ([]*types.KeyValue, error) { 200 kvdb := dbm.NewKVDB(db) 201 table := NewHeaderTable(kvdb) 202 203 err := table.Replace(header) 204 if err != nil { 205 return nil, err 206 } 207 208 kvs, err := table.Save() 209 if err != nil { 210 return nil, err 211 } 212 return kvs, nil 213 } 214 215 //通过指定的index获取对应的blockheader 216 //通过高度获取:height+hash;indexName="",prefix=nil,primaryKey=calcHeightHashKey 217 //通过index获取:hash; indexName="hash",prefix=HeaderRow.Get(indexName),primaryKey=nil 218 func getHeaderByIndex(db dbm.DB, indexName string, prefix []byte, primaryKey []byte) (*types.Header, error) { 219 kvdb := dbm.NewKVDB(db) 220 table := NewHeaderTable(kvdb) 221 222 rows, err := table.ListIndex(indexName, prefix, primaryKey, 0, dbm.ListASC) 223 if err != nil { 224 return nil, err 225 } 226 if len(rows) != 1 { 227 panic("getHeaderByIndex") 228 } 229 header, ok := rows[0].Data.(*types.Header) 230 if !ok { 231 return nil, types.ErrDecode 232 } 233 return header, nil 234 } 235 236 /* 237 table paratx 238 data: types.HeightPara 239 primary:heighttitle 240 index: height,title 241 */ 242 var paratxOpt = &table.Option{ 243 Prefix: "CHAIN-paratx", 244 Name: "paratx", 245 Primary: "heighttitle", 246 Index: []string{"height", "title"}, 247 } 248 249 //ParaTxRow table meta 结构 250 type ParaTxRow struct { 251 *types.HeightPara 252 } 253 254 //NewParaTxRow 新建一个meta 结构 255 func NewParaTxRow() *ParaTxRow { 256 return &ParaTxRow{HeightPara: &types.HeightPara{}} 257 } 258 259 //NewParaTxTable 新建表 260 func NewParaTxTable(kvdb dbm.KV) *table.Table { 261 rowmeta := NewParaTxRow() 262 table, err := table.NewTable(rowmeta, kvdb, paratxOpt) 263 if err != nil { 264 panic(err) 265 } 266 return table 267 } 268 269 //CreateRow 新建数据行 270 func (paratx *ParaTxRow) CreateRow() *table.Row { 271 return &table.Row{Data: &types.HeightPara{}} 272 } 273 274 //SetPayload 设置数据 275 func (paratx *ParaTxRow) SetPayload(data types.Message) error { 276 if heightPara, ok := data.(*types.HeightPara); ok { 277 paratx.HeightPara = heightPara 278 return nil 279 } 280 return types.ErrTypeAsset 281 } 282 283 //Get 获取索引对应的key值 284 func (paratx *ParaTxRow) Get(key string) ([]byte, error) { 285 if key == "heighttitle" { 286 return calcHeightTitleKey(paratx.Height, paratx.Title), nil 287 } else if key == "height" { 288 return calcHeightParaKey(paratx.Height), nil 289 } else if key == "title" { 290 return []byte(paratx.Title), nil 291 } 292 return nil, types.ErrNotFound 293 } 294 295 //saveParaTxTable 保存平行链标识 296 func saveParaTxTable(cfg *types.TuringchainConfig, db dbm.DB, height int64, hash []byte, txs []*types.Transaction) ([]*types.KeyValue, error) { 297 kvdb := dbm.NewKVDB(db) 298 table := NewParaTxTable(kvdb) 299 if !cfg.IsFork(height, "ForkRootHash") { 300 for _, tx := range txs { 301 exec := string(tx.Execer) 302 if types.IsParaExecName(exec) { 303 if title, ok := types.GetParaExecTitleName(exec); ok { 304 var paratx = &types.HeightPara{Height: height, Title: title, Hash: hash} 305 err := table.Replace(paratx) 306 if err != nil { 307 return nil, err 308 } 309 } 310 } 311 } 312 } else { 313 //交易分类排序之后需要存储各个链的子roothash 314 _, childhashs := merkle.CalcMultiLayerMerkleInfo(cfg, height, txs) 315 for i, childhash := range childhashs { 316 var paratx = &types.HeightPara{ 317 Height: height, 318 Hash: hash, 319 Title: childhash.Title, 320 ChildHash: childhash.ChildHash, 321 StartIndex: childhash.StartIndex, 322 ChildHashIndex: uint32(i), 323 TxCount: childhash.GetTxCount(), 324 } 325 err := table.Replace(paratx) 326 if err != nil { 327 return nil, err 328 } 329 } 330 331 } 332 kvs, err := table.Save() 333 if err != nil { 334 return nil, err 335 } 336 return kvs, nil 337 } 338 339 //delParaTxTable 删除平行链标识 340 //删除本高度对应的所有平行链的标识 341 func delParaTxTable(db dbm.DB, height int64) ([]*types.KeyValue, error) { 342 kvdb := dbm.NewKVDB(db) 343 table := NewParaTxTable(kvdb) 344 rows, _ := table.ListIndex("height", calcHeightParaKey(height), nil, 0, dbm.ListASC) 345 for _, row := range rows { 346 err := table.Del(row.Primary) 347 if err != nil { 348 return nil, err 349 } 350 } 351 kvs, err := table.Save() 352 if err != nil { 353 return nil, err 354 } 355 return kvs, nil 356 } 357 358 //通过指定的index获取对应的ParaTx信息 359 //通过height高度获取:indexName="height",prefix=HeaderRow.Get(indexName) 360 //通过title获取; indexName="title",prefix=HeaderRow.Get(indexName) 361 func getParaTxByIndex(db dbm.DB, indexName string, prefix []byte, primaryKey []byte, count, direction int32) (*types.HeightParas, error) { 362 kvdb := dbm.NewKVDB(db) 363 table := NewParaTxTable(kvdb) 364 365 rows, err := table.ListIndex(indexName, prefix, primaryKey, count, direction) 366 if err != nil { 367 return nil, err 368 } 369 var rep types.HeightParas 370 for _, row := range rows { 371 r, ok := row.Data.(*types.HeightPara) 372 if !ok { 373 return nil, types.ErrDecode 374 } 375 rep.Items = append(rep.Items, r) 376 } 377 return &rep, nil 378 } 379 380 /* 381 table receipt 382 data: block receipt 383 index: hash 384 */ 385 var receiptOpt = &table.Option{ 386 Prefix: "CHAIN-receipt", 387 Name: "receipt", 388 Primary: "heighthash", 389 Index: []string{"hash"}, 390 } 391 392 //NewReceiptTable 新建表 393 func NewReceiptTable(kvdb dbm.KV) *table.Table { 394 rowmeta := NewReceiptRow() 395 table, err := table.NewTable(rowmeta, kvdb, receiptOpt) 396 if err != nil { 397 panic(err) 398 } 399 return table 400 } 401 402 //ReceiptRow table meta 结构 403 type ReceiptRow struct { 404 *types.BlockReceipt 405 } 406 407 //NewReceiptRow 新建一个meta 结构 408 func NewReceiptRow() *ReceiptRow { 409 return &ReceiptRow{BlockReceipt: &types.BlockReceipt{}} 410 } 411 412 //CreateRow 新建数据行 413 func (recpt *ReceiptRow) CreateRow() *table.Row { 414 return &table.Row{Data: &types.BlockReceipt{}} 415 } 416 417 //SetPayload 设置数据 418 func (recpt *ReceiptRow) SetPayload(data types.Message) error { 419 if blockReceipt, ok := data.(*types.BlockReceipt); ok { 420 recpt.BlockReceipt = blockReceipt 421 return nil 422 } 423 return types.ErrTypeAsset 424 } 425 426 //Get 获取索引对应的key值 427 func (recpt *ReceiptRow) Get(key string) ([]byte, error) { 428 if key == "heighthash" { 429 return calcHeightHashKey(recpt.Height, recpt.Hash), nil 430 } else if key == "hash" { 431 return recpt.Hash, nil 432 } 433 return nil, types.ErrNotFound 434 } 435 436 //saveBlockReceiptTable 保存block receipt 437 func saveBlockReceiptTable(db dbm.DB, recpt *types.BlockReceipt) ([]*types.KeyValue, error) { 438 kvdb := dbm.NewKVDB(db) 439 table := NewReceiptTable(kvdb) 440 441 err := table.Replace(recpt) 442 if err != nil { 443 return nil, err 444 } 445 446 kvs, err := table.Save() 447 if err != nil { 448 return nil, err 449 } 450 return kvs, nil 451 } 452 453 //通过指定的index获取对应的blockReceipt 454 //通过高度获取:height+hash;indexName="",prefix=nil,primaryKey=calcHeightHashKey 455 //通过index获取:hash; indexName="hash",prefix=ReceiptRow.Get(indexName),primaryKey=nil 456 func getReceiptByIndex(db dbm.DB, indexName string, prefix []byte, primaryKey []byte) (*types.BlockReceipt, error) { 457 kvdb := dbm.NewKVDB(db) 458 table := NewReceiptTable(kvdb) 459 460 rows, err := table.ListIndex(indexName, prefix, primaryKey, 0, dbm.ListASC) 461 if err != nil { 462 return nil, err 463 } 464 if len(rows) != 1 { 465 panic("getReceiptByIndex") 466 } 467 recpt, ok := rows[0].Data.(*types.BlockReceipt) 468 if !ok { 469 return nil, types.ErrDecode 470 } 471 return recpt, nil 472 } 473 474 //delBlockReceiptTable 删除block receipt 475 func delBlockReceiptTable(db dbm.DB, height int64, hash []byte) ([]*types.KeyValue, error) { 476 kvdb := dbm.NewKVDB(db) 477 table := NewReceiptTable(kvdb) 478 479 err := table.Del(calcHeightHashKey(height, hash)) 480 if err != nil { 481 return nil, err 482 } 483 484 kvs, err := table.Save() 485 if err != nil { 486 return nil, err 487 } 488 return kvs, nil 489 }