diff --git a/block/block.go b/block/block.go new file mode 100644 index 0000000..fe56a31 --- /dev/null +++ b/block/block.go @@ -0,0 +1,27 @@ +package block + +import ( + "bytes" + "crypto/sha256" +) + +type Block struct { + Data []byte // this block's data + Hash []byte // this block's hash + Link []byte // the hash of the last block in the chain. this is the key part that links the blocks together +} + +func (b *Block) DeriveHash() []byte { + blockInfo := bytes.Join([][]byte{b.Data, b.Link}, []byte{}) + hash := sha256.Sum256(blockInfo) + return hash[:] +} + +func New(data []byte, link []byte) *Block { + block := &Block{ + Data: data, + Link: link, + } + block.Hash = block.DeriveHash() + return block +} diff --git a/chain/chain.go b/chain/chain.go new file mode 100644 index 0000000..b7136a8 --- /dev/null +++ b/chain/chain.go @@ -0,0 +1,23 @@ +package chain + +import ( + "github.com/alanvivona/blockchaingo/block" +) + +type Chain struct { + Blocks []*block.Block +} + +func (c *Chain) AddBlock(data []byte) { + lastBlock := c.Blocks[len(c.Blocks)-1] + newBlock := block.New(data, lastBlock.Hash) + c.Blocks = append(c.Blocks, newBlock) +} + +func New() *Chain { + return &Chain{ + Blocks: []*block.Block{ + block.New([]byte("Genesis Block"), []byte{}), + }, + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0f9eab8 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module github.com/alanvivona/blockchaingo + +go 1.14 + +require ( + github.com/gizak/termui/v3 v3.1.0 + github.com/sirupsen/logrus v1.6.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e99a6c1 --- /dev/null +++ b/go.sum @@ -0,0 +1,17 @@ +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gizak/termui v3.1.0+incompatible h1:N3CFm+j087lanTxPpHOmQs0uS3s5I9TxoAFy6DqPqv8= +github.com/gizak/termui/v3 v3.1.0 h1:ZZmVDgwHl7gR7elfKf1xc4IudXZ5qqfDh4wExk4Iajc= +github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/mattn/go-runewidth v0.0.2 h1:UnlwIPBGaTZfPQ6T1IGzPI0EkYAQmT9fAEJ/poFC63o= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= +github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840= +github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/main.go b/main.go new file mode 100644 index 0000000..d70989d --- /dev/null +++ b/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + + "github.com/alanvivona/blockchaingo/chain" + "github.com/alanvivona/blockchaingo/ui" +) + +func main() { + + // create a new blockchain and add the 1st block "Genesis" + blockchain := chain.New() + + // add 9 more blocks to the chain + for i := 2; i < 11; i++ { + message := fmt.Sprintf("Block number %d!", i) + blockchain.AddBlock([]byte(message)) + } + + // print the whole blockchain + for _, block := range blockchain.Blocks { + ui.PrintBlock(block) + } + +} diff --git a/ui/ui.go b/ui/ui.go new file mode 100644 index 0000000..3bfde55 --- /dev/null +++ b/ui/ui.go @@ -0,0 +1,21 @@ +package ui + +import ( + "encoding/hex" + + "github.com/alanvivona/blockchaingo/block" + "github.com/sirupsen/logrus" +) + +func HashBytesToString(hash []byte) string { + encoded := make([]byte, hex.EncodedLen(len(hash))) + hex.Encode(encoded, hash) + return string(encoded) +} + +func PrintBlock(b *block.Block) { + logrus.WithFields(logrus.Fields{ + "hash": HashBytesToString(b.Hash), + "link": HashBytesToString(b.Link), + }).Info(string(b.Data)) +}