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  }