aboutsummaryrefslogtreecommitdiff
path: root/pkg/blockchain/chainwriter/chainwriter.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/blockchain/chainwriter/chainwriter.go')
-rw-r--r--pkg/blockchain/chainwriter/chainwriter.go127
1 files changed, 127 insertions, 0 deletions
diff --git a/pkg/blockchain/chainwriter/chainwriter.go b/pkg/blockchain/chainwriter/chainwriter.go
new file mode 100644
index 0000000..67a7d49
--- /dev/null
+++ b/pkg/blockchain/chainwriter/chainwriter.go
@@ -0,0 +1,127 @@
+package chainwriter
+
+import (
+ "Chain/pkg/block"
+ "Chain/pkg/blockchain/blockinfodatabase"
+ "Chain/pkg/pro"
+ "Chain/pkg/utils"
+ "google.golang.org/protobuf/proto"
+ "log"
+ "os"
+)
+
+// ChainWriter handles all I/O for the BlockChain. It stores and retrieves
+// Blocks and UndoBlocks.
+// See config.go for more information on its fields.
+// Block files are of the format:
+// "DataDirectory/BlockFileName_CurrentBlockFileNumber.FileExtension"
+// Ex: "data/block_0.txt"
+// UndoBlock files are of the format:
+// "DataDirectory/UndoFileName_CurrentUndoFileNumber.FileExtension"
+// Ex: "data/undo_0.txt"
+type ChainWriter struct {
+ // data storage information
+ FileExtension string
+ DataDirectory string
+
+ // block information
+ BlockFileName string
+ CurrentBlockFileNumber uint32
+ CurrentBlockOffset uint32
+ MaxBlockFileSize uint32
+
+ // undo block information
+ UndoFileName string
+ CurrentUndoFileNumber uint32
+ CurrentUndoOffset uint32
+ MaxUndoFileSize uint32
+}
+
+// New returns a ChainWriter given a Config.
+func New(config *Config) *ChainWriter {
+ if err := os.MkdirAll(config.DataDirectory, 0700); err != nil {
+ log.Fatalf("Could not create ChainWriter's data directory")
+ }
+ return &ChainWriter{
+ FileExtension: config.FileExtension,
+ DataDirectory: config.DataDirectory,
+ BlockFileName: config.BlockFileName,
+ CurrentBlockFileNumber: 0,
+ CurrentBlockOffset: 0,
+ MaxBlockFileSize: config.MaxBlockFileSize,
+ UndoFileName: config.UndoFileName,
+ CurrentUndoFileNumber: 0,
+ CurrentUndoOffset: 0,
+ MaxUndoFileSize: config.MaxUndoFileSize,
+ }
+}
+
+// StoreBlock stores a Block and its corresponding UndoBlock to Disk,
+// returning a BlockRecord that contains information for later retrieval.
+func (cw *ChainWriter) StoreBlock(bl *block.Block, undoBlock *UndoBlock, height uint32) *blockinfodatabase.BlockRecord {
+ // serialize block
+ b := block.EncodeBlock(bl)
+ serializedBlock, err := proto.Marshal(b)
+ if err != nil {
+ utils.Debug.Printf("Failed to marshal block")
+ }
+ // serialize undo block
+ ub := EncodeUndoBlock(undoBlock)
+ serializedUndoBlock, err := proto.Marshal(ub)
+ if err != nil {
+ utils.Debug.Printf("Failed to marshal undo block")
+ }
+ // write block to disk
+ bfi := cw.WriteBlock(serializedBlock)
+ // create an empty file info, which we will update if the function is passed an undo block.
+ ufi := &FileInfo{}
+ if undoBlock.Amounts != nil {
+ ufi = cw.WriteUndoBlock(serializedUndoBlock)
+ }
+
+ return &blockinfodatabase.BlockRecord{
+ Header: bl.Header,
+ Height: height,
+ NumberOfTransactions: uint32(len(bl.Transactions)),
+ BlockFile: bfi.FileName,
+ BlockStartOffset: bfi.StartOffset,
+ BlockEndOffset: bfi.EndOffset,
+ UndoFile: ufi.FileName,
+ UndoStartOffset: ufi.StartOffset,
+ UndoEndOffset: ufi.EndOffset,
+ }
+}
+
+// WriteBlock writes a serialized Block to Disk and returns
+// a FileInfo for storage information.
+func (cw *ChainWriter) WriteBlock(serializedBlock []byte) *FileInfo {
+ //TODO
+ return nil
+}
+
+// WriteUndoBlock writes a serialized UndoBlock to Disk and returns
+// a FileInfo for storage information.
+func (cw *ChainWriter) WriteUndoBlock(serializedUndoBlock []byte) *FileInfo {
+ //TODO
+ return nil
+}
+
+// ReadBlock returns a Block given a FileInfo.
+func (cw *ChainWriter) ReadBlock(fi *FileInfo) *block.Block {
+ bytes := readFromDisk(fi)
+ pb := &pro.Block{}
+ if err := proto.Unmarshal(bytes, pb); err != nil {
+ utils.Debug.Printf("failed to unmarshal block from file info {%v}", fi)
+ }
+ return block.DecodeBlock(pb)
+}
+
+// ReadUndoBlock returns an UndoBlock given a FileInfo.
+func (cw *ChainWriter) ReadUndoBlock(fi *FileInfo) *UndoBlock {
+ bytes := readFromDisk(fi)
+ pub := &pro.UndoBlock{}
+ if err := proto.Unmarshal(bytes, pub); err != nil {
+ utils.Debug.Printf("failed to unmarshal undo block from file info {%v}", fi)
+ }
+ return DecodeUndoBlock(pub)
+}