package core import ( "crypto/sha512" "encoding/binary" "github.com/matchsystems/werr" "mic-wallet/common" "mic-wallet/server/repository/entities" "sync" ) type Block struct { Id int64 PrevHash []byte Hash []byte TXs map[string]*common.NewTxOpts // If there is some transactions added after block is finished TXsLeftOver map[string]*common.NewTxOpts IgnoreSignatures map[string]struct{} Lock *sync.RWMutex IsFinished bool } func NewBlock(id int64, prevHash []byte, prevTxsLeftOver map[string]*common.NewTxOpts, txsLeftOver map[string]*common.NewTxOpts) *Block { return &Block{ Id: id, IgnoreSignatures: make(map[string]struct{}), TXs: prevTxsLeftOver, TXsLeftOver: txsLeftOver, Lock: &sync.RWMutex{}, PrevHash: prevHash, } } func (b *Block) AddTx(tx *common.NewTxOpts) error { b.Lock.Lock() sigStr := tx.SignatureString() hashStr := tx.HashString() if _, ok := b.IgnoreSignatures[sigStr]; ok { return werr.Wrapf(common.ErrEntityExists, "transaction with signature %s already exists", sigStr) } if !b.IsFinished { b.TXs[hashStr] = tx } else { b.TXsLeftOver[hashStr] = tx } b.Lock.Unlock() return nil } func (b *Block) Finish() ([]byte, error) { hash := sha512.New() if err := binary.Write(hash, binary.BigEndian, b.Id); err != nil { return nil, werr.Wrapf(err, "failed to write block id into hash buffer for block %d", b.Id) } b.Lock.Lock() hash.Write(b.PrevHash) for _, tx := range b.TXs { hash.Write(tx.Hash) } b.IsFinished = true b.Lock.Unlock() b.Hash = hash.Sum(nil) return b.Hash, nil } func (b *Block) ToRepoEntity() *entities.Block { return &entities.Block{ Id: b.Id, Hash: b.Hash, PrevHash: b.PrevHash, } }