77 lines
1.8 KiB
Go
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,
|
|
}
|
|
}
|