neoneo-go/pkg/chain/chain.go

92 lines
2.7 KiB
Go
Raw Normal View History

package chain
import (
"errors"
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction"
"github.com/CityOfZion/neo-go/pkg/database"
"github.com/CityOfZion/neo-go/pkg/wire/payload"
)
var (
// ErrBlockAlreadyExists happens when you try to save the same block twice
ErrBlockAlreadyExists = errors.New("this block has already been saved in the database")
)
// Chain represents a blockchain instance
type Chain struct {
db *Chaindb
}
//New returns a new chain instance
func New(db database.Database) *Chain {
return &Chain{
db: &Chaindb{db},
}
}
// SaveBlock verifies and saves the block in the database
// XXX: for now we will just save without verifying the block
// This function is called by the server and if an error is returned then
// the server informs the sync manager to redownload the block
// XXX:We should also check if the header is already saved in the database
// If not, then we need to validate the header with the rest of the chain
// For now we re-save the header
func (c *Chain) SaveBlock(msg payload.BlockMessage) error {
err := c.VerifyBlock(msg.Block)
if err != nil {
return err
}
//XXX(Issue): We can either check the hash here for genesisblock.
//We most likely will have it anyways after validation/ We can return it from VerifyBlock
// Or we can do it somewhere in startup, performance benefits
// won't be that big since it's just a bytes.Equal.
// so it's more about which is more readable and where it makes sense to put
return c.db.saveBlock(msg.Block, false)
}
// VerifyBlock verifies whether a block is valid according
// to the rules of consensus
func (c *Chain) VerifyBlock(block payload.Block) error {
// Check if we already have this block
// XXX: We can optimise by implementing a Has method
// caching the last block in memory
lastBlock, err := c.db.GetLastBlock()
if err != nil {
return err
}
// Check if we have already saved this block
// by looking if the latest block height is more than
// incoming block height
if lastBlock.Index > block.Index {
return ErrBlockAlreadyExists
}
return nil
}
// VerifyTx verifies whether a transaction is valid according
// to the rules of consensus
func (c *Chain) VerifyTx(tx transaction.Transactioner) error {
return nil
}
// SaveHeaders will save the set of headers without validating
func (c *Chain) SaveHeaders(msg payload.HeadersMessage) error {
err := c.verifyHeaders(msg.Headers)
if err != nil {
return err
}
return c.db.saveHeaders(msg.Headers)
}
// verifyHeaders will be used to verify a batch of headers
// should only ever be called during the initial block download
// or when the node receives a HeadersMessage
func (c *Chain) verifyHeaders(hdrs []*payload.BlockBase) error {
return nil
}