github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/consensus/datong/snapshot.go (about)

     1  package datong
     2  
     3  import (
     4  	"errors"
     5  
     6  	"github.com/FusionFoundation/efsn/common"
     7  	"github.com/FusionFoundation/efsn/core/types"
     8  	"github.com/FusionFoundation/efsn/crypto"
     9  )
    10  
    11  // Snapshot wacom
    12  type Snapshot struct {
    13  	Selected     common.Hash   `json:"selected"`
    14  	Retreat      []common.Hash `json:"retreat"`
    15  	TicketNumber int           `json:"ticketNumber"`
    16  }
    17  
    18  type ticketLogType byte
    19  
    20  const (
    21  	ticketSelect ticketLogType = iota + 1
    22  	ticketRetreat
    23  )
    24  
    25  type ticketLog struct {
    26  	TicketID common.Hash
    27  	Type     ticketLogType
    28  }
    29  
    30  type snapshot struct {
    31  	logs         []*ticketLog
    32  	ticketNumber int
    33  }
    34  
    35  func newSnapshot() *snapshot {
    36  	return &snapshot{
    37  		logs: make([]*ticketLog, 0),
    38  	}
    39  
    40  }
    41  
    42  func newSnapshotWithData(data []byte) (*snapshot, error) {
    43  	snap := newSnapshot()
    44  	if err := snap.SetBytes(data); err != nil {
    45  		return nil, err
    46  	}
    47  	return snap, nil
    48  }
    49  
    50  // NewSnapshotFromHeader wacom
    51  func NewSnapshotFromHeader(header *types.Header) (*Snapshot, error) {
    52  	snap, err := newSnapshotWithData(getSnapDataByHeader(header))
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	return snap.ToShow(), nil
    57  }
    58  
    59  func (snap *snapshot) GetVoteTicket() common.Hash {
    60  	if len(snap.logs) > 0 && snap.logs[0].Type == ticketSelect {
    61  		return snap.logs[0].TicketID
    62  	}
    63  	return common.Hash{}
    64  }
    65  
    66  func (snap *snapshot) AddLog(log *ticketLog) {
    67  	snap.logs = append(snap.logs, log)
    68  }
    69  
    70  func (snap *snapshot) SetBytes(data []byte) error {
    71  	if len(data) <= 0 {
    72  		return errors.New("Empty data")
    73  	}
    74  
    75  	realData := data[:len(data)-1]
    76  	check := data[len(data)-1]
    77  
    78  	if calcCheck(realData) != check {
    79  		return errors.New("check error")
    80  	}
    81  
    82  	snap.ticketNumber = common.BytesToInt(realData[:4])
    83  
    84  	realData = realData[4:]
    85  	dataLength := len(realData)
    86  	logLength := common.HashLength + 1
    87  
    88  	if dataLength%logLength != 0 {
    89  		return errors.New("data length error")
    90  	}
    91  
    92  	count := dataLength / logLength
    93  	snap.logs = make([]*ticketLog, count)
    94  	for i := 0; i < count; i++ {
    95  		base := logLength * i
    96  		snap.logs[i] = &ticketLog{
    97  			TicketID: common.BytesToHash(realData[base : logLength+base-1]),
    98  			Type:     ticketLogType(realData[logLength+base-1]),
    99  		}
   100  	}
   101  
   102  	return nil
   103  }
   104  
   105  func (snap *snapshot) Bytes() []byte {
   106  	data := make([]byte, 0)
   107  
   108  	data = append(data, common.IntToBytes(snap.ticketNumber)...)
   109  
   110  	for i := 0; i < len(snap.logs); i++ {
   111  		data = append(data, snap.logs[i].TicketID[:]...)
   112  		data = append(data, byte(snap.logs[i].Type))
   113  	}
   114  
   115  	data = append(data, calcCheck(data))
   116  	return data
   117  }
   118  
   119  func (snap *snapshot) TicketNumber() int {
   120  	return snap.ticketNumber
   121  }
   122  
   123  func (snap *snapshot) SetTicketNumber(ticketNumber int) {
   124  	snap.ticketNumber = ticketNumber
   125  }
   126  
   127  func (snap *snapshot) ToShow() *Snapshot {
   128  	var retreat []common.Hash
   129  	if len(snap.logs) == 0 {
   130  		retreat = make([]common.Hash, 0, 0)
   131  	} else {
   132  		retreat = make([]common.Hash, 0, len(snap.logs)-1)
   133  		for i := 1; i < len(snap.logs); i++ {
   134  			if snap.logs[i].Type == ticketRetreat {
   135  				retreat = append(retreat, snap.logs[i].TicketID)
   136  			}
   137  		}
   138  	}
   139  	return &Snapshot{
   140  		Selected:     snap.GetVoteTicket(),
   141  		Retreat:      retreat,
   142  		TicketNumber: snap.ticketNumber,
   143  	}
   144  }
   145  
   146  func calcCheck(data []byte) byte {
   147  	hash := crypto.Keccak256Hash(data)
   148  	return hash[0]
   149  }
   150  
   151  func GenerateGenesisExtraData(old []byte, ticketNumber uint64) []byte {
   152  	snap := newSnapshot()
   153  	snap.SetTicketNumber(int(ticketNumber))
   154  	snapBytes := snap.Bytes()
   155  
   156  	extraData := make([]byte, extraVanity)
   157  	copy(extraData[:], old)
   158  
   159  	extraData = append(extraData, snapBytes...)
   160  
   161  	if len(old) >= extraVanity+extraSeal {
   162  		extraData = append(extraData, old[len(old)-extraSeal:]...)
   163  	} else {
   164  		extraData = append(extraData, make([]byte, extraSeal)...)
   165  	}
   166  	return extraData
   167  }