diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 9bc97d1..e76e88a 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -3,27 +3,38 @@ package blockchain import ( "crypto/sha256" "encoding/binary" + "encoding/gob" + "io" ) +// Hash represents a hash of a block or transaction +type Hash [32]byte + +// BlockHeader contains metadata about a block type BlockHeader struct { blockNumber uint32 lastBlock Hash miner Wallet } +// Marshal converts a BlockHeader to a byte slice func (bh *BlockHeader) Marshal() []byte { buf := []byte{} binary.LittleEndian.PutUint32(buf, bh.blockNumber) - buf = append(buf, bh.lastBlock...) + for _, b := range bh.lastBlock { + buf = append(buf, b) + } buf = append(buf, bh.miner.Marshal()...) return buf } +// Block represents a block in the blockchain. Contains transactions and header metadata. type Block struct { BlockHeader - transactions []Transaction + transactions []*Transaction } +// Marshal converts a Block to a byte slice func (b *Block) Marshal() []byte { buf := b.BlockHeader.Marshal() for _, t := range b.transactions { @@ -32,13 +43,33 @@ func (b *Block) Marshal() []byte { return buf } -func (b *Block) Hash() []byte { - sum := sha256.Sum256(b.Marshal()) - return sum[:] +// Encode writes the marshalled block to the given io.Writer +func (b *Block) Encode(w io.Writer) { + gob.NewEncoder(w).Encode(b) +} + +// Encode reads the marshalled block from the given io.Reader +func (b *Block) Decode(r io.Reader) { + gob.NewDecoder(r).Decode(b) } -type BlockChain []Block +// Hash computes and returns the SHA256 hash of the block +func (b *Block) Hash() Hash { + return sha256.Sum256(b.Marshal()) +} + +// BlockChain represents a linked list of blocks +type BlockChain struct { + blocks []*Block + head Hash +} -func (bc BlockChain) Verify(b *Block) { +// Encode writes the marshalled blockchain to the given io.Writer +func (b *BlockChain) Encode(w io.Writer) { + gob.NewEncoder(w).Encode(b) +} +// Encode reads the marshalled blockchain from the given io.Reader +func (b *BlockChain) Decode(r io.Reader) { + gob.NewDecoder(r).Decode(b) } diff --git a/blockchain/transaction.go b/blockchain/transaction.go index 847d250..a63f195 100644 --- a/blockchain/transaction.go +++ b/blockchain/transaction.go @@ -1,36 +1,35 @@ package blockchain -import ( - "encoding/binary" -) +import "encoding/binary" // TxHashPointer is a reference to a transaction on the blockchain. type TxHashPointer struct { blockNumber uint32 - hash []byte + hash Hash } +// Marshal converts a TxHashPointer to a byte slice func (thp TxHashPointer) Marshal() []byte { buf := []byte{} binary.LittleEndian.PutUint32(buf, thp.blockNumber) - return append(buf, thp.hash...) + for _, b := range thp.hash { + buf = append(buf, b) + } + return buf } // TxBody contains all relevant information about a transaction. type TxBody struct { - sender Wallet - inputs []TxHashPointer - outputs []TxHashPointer + sender Wallet + input TxHashPointer + output TxHashPointer } -func (tb *TxBody) Marshal() []byte { +// Marshal converts a TxBody to a byte slice +func (tb TxBody) Marshal() []byte { buf := tb.sender.Marshal() - for _, input := range tb.inputs { - buf = append(buf, input.Marshal()...) - } - for _, output := range tb.outputs { - buf = append(buf, output.Marshal()...) - } + buf = append(buf, tb.input.Marshal()...) + buf = append(buf, tb.output.Marshal()...) return buf } @@ -41,9 +40,12 @@ type Transaction struct { sig Signature } +// Marshal converts a Transaction to a byte slice func (t *Transaction) Marshal() []byte { buf := t.TxBody.Marshal() - buf = append(buf, t.hash...) + for _, b := range t.hash { + buf = append(buf, b) + } buf = append(buf, t.sig.X.Bytes()...) buf = append(buf, t.sig.Y.Bytes()...) return buf diff --git a/blockchain/wallet.go b/blockchain/wallet.go index 0f99636..3ce9a5c 100644 --- a/blockchain/wallet.go +++ b/blockchain/wallet.go @@ -8,14 +8,12 @@ import ( "math/big" ) +// The curve we use for our ECC crypto. var curve = elliptic.P256() // Wallet represents a Cumulus wallet address in the blockchain. type Wallet ecdsa.PublicKey -// Hash represents a hash of a transaction. -type Hash []byte - // Signature represents a signature of a transaction. type Signature struct { X big.Int @@ -23,7 +21,7 @@ type Signature struct { } // New creates a new Wallet backed by a ECC key pair. Uses system entropy. -func NewWallet() (*Wallet, error) { +func newWallet() (*Wallet, error) { k, err := ecdsa.GenerateKey(curve, rand.Reader) if err != nil { return nil, err @@ -32,19 +30,17 @@ func NewWallet() (*Wallet, error) { return &pk, nil } +// String returns a human-readable string representation of a wallet func (w *Wallet) String() string { return fmt.Sprintf("%x-%x", w.X, w.Y) } +// Marshal converts the Wallet to a byte slice func (w *Wallet) Marshal() []byte { return elliptic.Marshal(curve, w.X, w.Y) } +// Equals checks whether two wallets are the same. func (w *Wallet) Equals(other *Wallet) bool { return w.X.Cmp(other.X) == 0 && w.Y.Cmp(other.Y) == 0 } - -func Unmarshal(wallet []byte) *Wallet { - x, y := elliptic.Unmarshal(curve, wallet) - return &Wallet{curve, x, y} -} diff --git a/blockchain/wallet_test.go b/blockchain/wallet_test.go deleted file mode 100644 index 76f922d..0000000 --- a/blockchain/wallet_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package blockchain - -import ( - "fmt" - "testing" -) - -func TestUnmarshal(t *testing.T) { - w, err := NewWallet() - if err != nil { - t.Fail() - } - - unmarshalled := Unmarshal(w.Marshal()) - fmt.Println("w", w.X, w.Y) - fmt.Println("u", unmarshalled.X, unmarshalled.Y) - if !w.Equals(unmarshalled) { - t.Fatal("Unmarshal produced a different wallet") - } -}