diff --git a/pkg/chain/chain.go b/pkg/chain/chain.go new file mode 100644 index 000000000..c1492cb8f --- /dev/null +++ b/pkg/chain/chain.go @@ -0,0 +1,91 @@ +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 +}