micw/server/core/blocks_creator.go

88 lines
2.8 KiB
Go
Raw Normal View History

2024-11-17 21:24:19 +00:00
package core
import (
"context"
"errors"
"github.com/matchsystems/werr"
"mic-wallet/common"
"time"
)
2024-11-24 14:04:52 +00:00
var ErrOutOfDateBlockId = errors.New("")
var ErrBlockIdDoesntExist = errors.New("")
2024-11-17 21:24:19 +00:00
type IBlocksCreator interface {
Run(ctx context.Context) error
WriteTx(opts *common.NewTxOpts) error
// GetTx Searches for tx in every block
GetTx(block int64, hash string) *common.NewTxOpts
GetTxs() []*common.NewTxOpts
}
2024-11-24 14:04:52 +00:00
// BlocksCreator creates and rotates new Blocks and pushed them to the commiter
2024-11-17 21:24:19 +00:00
type BlocksCreator struct {
blocks map[int64]*Block
2024-11-24 14:04:52 +00:00
txsLeftOver map[string]*common.NewTxOpts
2024-11-17 21:24:19 +00:00
commiter IBlocksCommiter
prevBlockHash []byte
}
func NewBlocksCreator(commiter IBlocksCommiter) *BlocksCreator {
return &BlocksCreator{
2024-11-24 14:04:52 +00:00
blocks: make(map[int64]*Block),
txsLeftOver: make(map[string]*common.NewTxOpts),
commiter: commiter,
2024-11-17 21:24:19 +00:00
}
}
2024-11-24 14:04:52 +00:00
func (bc *BlocksCreator) Run(ctx context.Context) (err error) {
2024-11-17 21:24:19 +00:00
var blockID int64
2024-11-24 14:04:52 +00:00
var prevLeftOver map[string]*common.NewTxOpts
2024-11-17 21:24:19 +00:00
for {
blockID = common.GetBlockId(time.Now())
2024-11-24 14:04:52 +00:00
if oldBlock, ok := bc.blocks[blockID-common.BlockSecsDiff]; ok { // Commit and delete old block
// we need to know previous hash for new block.
// new transactions while oldBlock.Finish is executing will
// end up in leftOver so they will be parts of the next block
if bc.prevBlockHash, err = oldBlock.Finish(); err != nil {
return nil
}
go bc.commiter.CommitBlock(ctx, oldBlock) // may take a while
delete(bc.blocks, blockID-common.BlockSecsDiff)
2024-11-17 21:24:19 +00:00
}
2024-11-24 14:04:52 +00:00
// prevLeftOver becomes new block's transactions
// so there is no "lost" transactions
prevLeftOver = bc.txsLeftOver
// and also now we need to make new leftOver
bc.txsLeftOver = make(map[string]*common.NewTxOpts)
bc.blocks[blockID] = NewBlock(blockID, bc.prevBlockHash, prevLeftOver, bc.txsLeftOver)
// Waiting for the next block
time.Sleep(time.Until(time.Unix(blockID+common.BlockSecsDiff, 0)))
2024-11-17 21:24:19 +00:00
}
}
2024-11-24 14:04:52 +00:00
// WriteTx validates transaction and writes it into the current block
// if transaction is valid
2024-11-17 21:24:19 +00:00
func (bc *BlocksCreator) WriteTx(opts *common.NewTxOpts) error {
2024-11-24 14:04:52 +00:00
// validating may take some time, so to don't write into
if err := opts.Validate(); err != nil {
return werr.Wrapf(err,
"error validating transaction %s", opts.HashString())
}
2024-11-17 21:24:19 +00:00
currentBlockID := common.GetBlockId(time.Now())
if currentBlockID < opts.BlockId {
2024-11-24 14:04:52 +00:00
return werr.Wrapf(common.ErrEntityNotFound, "block id %d does not exist", currentBlockID)
2024-11-17 21:24:19 +00:00
} else if currentBlockID > opts.BlockId {
2024-11-24 14:04:52 +00:00
return werr.Wrapf(common.ErrEntityOutdated, "block id %d is out of date", currentBlockID)
}
block, ok := bc.blocks[currentBlockID]
if !ok {
return werr.Wrapf(common.ErrEntityNotFound, "block id %d does not exist", currentBlockID)
}
if err := block.AddTx(opts); err != nil {
return werr.Wrapf(err,
"error adding transaction to block %d", currentBlockID)
2024-11-17 21:24:19 +00:00
}
2024-11-24 14:04:52 +00:00
return nil
2024-11-17 21:24:19 +00:00
}