micw/server/core/block.go
2024-11-24 15:04:52 +01:00

77 lines
1.8 KiB
Go

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,
}
}