github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/store/mainchain/extstorages/league_block.go (about)

     1  package extstorages
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  
     7  	"math/big"
     8  
     9  	"io"
    10  
    11  	"github.com/syndtr/goleveldb/leveldb/util"
    12  	"github.com/sixexorg/magnetic-ring/common"
    13  	"github.com/sixexorg/magnetic-ring/common/sink"
    14  	"github.com/sixexorg/magnetic-ring/store/db"
    15  	scom "github.com/sixexorg/magnetic-ring/store/mainchain/common"
    16  	"github.com/sixexorg/magnetic-ring/store/mainchain/extstates"
    17  )
    18  
    19  type ExternalLeagueBlock struct {
    20  	enableCache bool
    21  	dbDir       string
    22  	store       *db.LevelDBStore
    23  }
    24  
    25  func NewExternalLeagueBlock(dbDir string, enableCache bool) (*ExternalLeagueBlock, error) {
    26  	store, err := db.NewLevelDBStore(dbDir)
    27  	if err != nil {
    28  		return nil, err
    29  	}
    30  	el := new(ExternalLeagueBlock)
    31  
    32  	el.enableCache = enableCache
    33  	el.dbDir = dbDir
    34  	el.store = store
    35  	return el, nil
    36  }
    37  
    38  //NewBatch start a commit batch
    39  func (this *ExternalLeagueBlock) NewBatch() {
    40  	this.store.NewBatch()
    41  }
    42  func (this *ExternalLeagueBlock) CommitTo() error {
    43  	return this.store.BatchCommit()
    44  }
    45  
    46  func (this *ExternalLeagueBlock) GetBlockHash(leagueId common.Address, height uint64) (common.Hash, error) {
    47  	key := this.getBlockHashKey(leagueId, height)
    48  	value, err := this.store.Get(key)
    49  	if err != nil {
    50  		return common.Hash{}, err
    51  	}
    52  	sk := sink.NewZeroCopySource(value)
    53  	blockHash, eof := sk.NextHash()
    54  	if eof {
    55  		return common.Hash{}, io.ErrUnexpectedEOF
    56  	}
    57  	return blockHash, nil
    58  }
    59  
    60  func (this *ExternalLeagueBlock) GetBlock(leagueId common.Address, height uint64) (*extstates.LeagueBlockSimple, error) {
    61  	hash, err := this.GetBlockHash(leagueId, height)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	key := this.getHeaderKey(hash)
    66  	val, err := this.store.Get(key)
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  	block := &extstates.LeagueBlockSimple{}
    71  	buff := bytes.NewBuffer(val)
    72  	err = block.Deserialize(buff)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  	return block, nil
    77  }
    78  
    79  func (this *ExternalLeagueBlock) GetBlockHashSpan(leagueId common.Address, left, right uint64) (hashArr common.HashArray, gasUsedSum *big.Int, err error) {
    80  	leftKey := this.getBlockHashKey(leagueId, left)
    81  	rightKey := this.getBlockHashKey(leagueId, right+1)
    82  	iter := this.store.NewSeniorIterator(&util.Range{
    83  		Start: leftKey,
    84  		Limit: rightKey,
    85  	})
    86  	hashes := make(common.HashArray, 0, right-left+1)
    87  	gasSum := big.NewInt(0)
    88  	for iter.Next() {
    89  		value := iter.Value()
    90  		sk := sink.NewZeroCopySource(value)
    91  		blockHash, eof := sk.NextHash()
    92  		if eof {
    93  			return nil, nil, io.ErrUnexpectedEOF
    94  		}
    95  		cp, eof := sk.NextComplex()
    96  		if eof {
    97  			return nil, nil, io.ErrUnexpectedEOF
    98  		}
    99  		gasUsed, err := cp.ComplexToBigInt()
   100  		if err != nil {
   101  			return nil, nil, err
   102  		}
   103  		gasSum.Add(gasSum, gasUsed)
   104  		hashes = append(hashes, blockHash)
   105  	}
   106  	iter.Release()
   107  	err = iter.Error()
   108  	if err != nil {
   109  		return nil, nil, err
   110  	}
   111  	return hashes, gasSum, nil
   112  }
   113  
   114  //SaveBlock persist block to store
   115  func (this *ExternalLeagueBlock) Save(block *extstates.LeagueBlockSimple) error {
   116  	blockHash := block.Header.Hash()
   117  	err := this.saveBlockHash(block.Header.LeagueId, block.Header.Height, blockHash, block.EnergyUsed)
   118  	if err != nil {
   119  		return err
   120  	}
   121  	buff := new(bytes.Buffer)
   122  	err = block.Serialize(buff)
   123  	if err != nil {
   124  		return err
   125  	}
   126  	key := this.getHeaderKey(blockHash)
   127  	this.store.BatchPut(key, buff.Bytes())
   128  	return nil
   129  }
   130  func (this *ExternalLeagueBlock) BatchSave(blocks []*extstates.LeagueBlockSimple) error {
   131  	leagueKey := make(map[common.Address]bool)
   132  	for _, v := range blocks {
   133  		leagueKey[v.Header.LeagueId] = true
   134  	}
   135  	var err error
   136  	for _, v := range blocks {
   137  		blockHash := v.Header.Hash()
   138  		err = this.saveBlockHash(v.Header.LeagueId, v.Header.Height, blockHash, v.EnergyUsed)
   139  		if err != nil {
   140  			return err
   141  		}
   142  		buff := new(bytes.Buffer)
   143  		err = v.Serialize(buff)
   144  		if err != nil {
   145  			return err
   146  		}
   147  		key := this.getHeaderKey(blockHash)
   148  		this.store.BatchPut(key, buff.Bytes())
   149  	}
   150  	return nil
   151  }
   152  
   153  func (this *ExternalLeagueBlock) saveBlockHash(leagueId common.Address, height uint64, blockHash common.Hash, gasUsed *big.Int) error {
   154  	key := this.getBlockHashKey(leagueId, height)
   155  	sk := sink.NewZeroCopySink(nil)
   156  	sk.WriteBytes(blockHash[:])
   157  	cp, err := sink.BigIntToComplex(gasUsed)
   158  	if err != nil {
   159  		return err
   160  	}
   161  	sk.WriteComplex(cp)
   162  	this.store.BatchPut(key, sk.Bytes())
   163  	return nil
   164  }
   165  func (this *ExternalLeagueBlock) getHeaderKey(blockHash common.Hash) []byte {
   166  	buff := make([]byte, 1+common.HashLength)
   167  	buff[0] = byte(scom.EXT_LEAGUE_DATA_HEADER)
   168  	copy(buff[1:common.HashLength+1], blockHash[:])
   169  	return buff
   170  }
   171  func (this *ExternalLeagueBlock) getBlockHashKey(leagueId common.Address, height uint64) []byte {
   172  	buff := make([]byte, 1+common.AddrLength+8)
   173  	buff[0] = byte(scom.EXT_LEAGUE_DATA_BLOCK)
   174  	copy(buff[1:common.AddrLength+1], leagueId[:])
   175  	binary.LittleEndian.PutUint64(buff[common.AddrLength+1:], height)
   176  	return buff
   177  }