Skip to content

Commit

Permalink
Merge 4475112 into 8fb32b0
Browse files Browse the repository at this point in the history
  • Loading branch information
jordanschalm committed May 13, 2017
2 parents 8fb32b0 + 4475112 commit 8969bc4
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 0 deletions.
57 changes: 57 additions & 0 deletions blockchain/block.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package blockchain

// BlockHeader contains metadata about a block
import (
"crypto/sha256"
"encoding/binary"
"encoding/gob"
"io"
)

// 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)
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
}

// Marshal converts a Block to a byte slice
func (b *Block) Marshal() []byte {
buf := b.BlockHeader.Marshal()
for _, t := range b.transactions {
buf = append(buf, t.Marshal()...)
}
return buf
}

// Encode writes the marshalled block to the given io.Writer
func (b *Block) Encode(w io.Writer) {
gob.NewEncoder(w).Encode(b)
}

// Decode reads the marshalled block from the given io.Reader
func (b *Block) Decode(r io.Reader) {
gob.NewDecoder(r).Decode(b)
}

// Hash computes and returns the SHA256 hash of the block
func (b *Block) Hash() Hash {
return sha256.Sum256(b.Marshal())
}
45 changes: 45 additions & 0 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package blockchain

import (
"encoding/gob"
"io"
)

// Hash represents a 256-bit hash of a block or transaction
type Hash [32]byte

// BlockChain represents a linked list of blocks
type BlockChain struct {
blocks []*Block
head Hash
}

// Encode writes the marshalled blockchain to the given io.Writer
func (bc *BlockChain) Encode(w io.Writer) {
gob.NewEncoder(w).Encode(bc)
}

// Decode reads the marshalled blockchain from the given io.Reader
func (bc *BlockChain) Decode(r io.Reader) {
gob.NewDecoder(r).Decode(bc)
}

// ValidTransaction checks whether a transaction is valid, assuming the blockchain is valid.
func (bc *BlockChain) ValidTransaction(t *Transaction) bool {
// Find the transaction input (I) in the chain (by hash)
// Check that output to sender in I is equal to outputs in T
// Verify signature of T
return false
}

// ValidBlock checks whether a block is valid
func (bc *BlockChain) ValidBlock(b *Block) bool {
for _, t := range b.transactions {
if !bc.ValidTransaction(t) {
return false
}
}
// Check that block number is one greater than last block
// Check that hash of last block is correct
return false
}
71 changes: 71 additions & 0 deletions blockchain/transaction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package blockchain

import (
"crypto/sha256"
"encoding/binary"
)

// TxHashPointer is a reference to a transaction on the blockchain.
type TxHashPointer struct {
blockNumber uint32
hash Hash
}

// Marshal converts a TxHashPointer to a byte slice
func (thp TxHashPointer) Marshal() []byte {
buf := []byte{}
binary.LittleEndian.PutUint32(buf, thp.blockNumber)
for _, b := range thp.hash {
buf = append(buf, b)
}
return buf
}

// TxOutput defines an output to a transaction
type TxOutput struct {
amount uint64
recipient Wallet
}

// Marshal converts a TxOutput to a byte slice
func (to TxOutput) Marshal() []byte {
buf := []byte{}
binary.LittleEndian.PutUint64(buf, to.amount)
buf = append(buf, to.recipient.Marshal()...)
return buf
}

// TxBody contains all relevant information about a transaction
type TxBody struct {
sender Wallet
input TxHashPointer
outputs []TxOutput
}

// Marshal converts a TxBody to a byte slice
func (tb TxBody) Marshal() []byte {
buf := tb.sender.Marshal()
buf = append(buf, tb.input.Marshal()...)
for _, out := range tb.outputs {
buf = append(buf, out.Marshal()...)
}
return buf
}

// Transaction contains a TxBody and a signature verifying it
type Transaction struct {
TxBody
sig Signature
}

// Marshal converts a Transaction to a byte slice
func (t *Transaction) Marshal() []byte {
buf := t.TxBody.Marshal()
buf = append(buf, t.sig.Marshal()...)
return buf
}

// Hash returns the SHA256 hash of a transaction
func (t *Transaction) Hash() Hash {
return sha256.Sum256(t.Marshal())
}
51 changes: 51 additions & 0 deletions blockchain/wallet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package blockchain

import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"fmt"
"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

// Signature represents a signature of a transaction.
type Signature struct {
X big.Int
Y big.Int
}

// Marshal converts a signature to a byte slice
func (s *Signature) Marshal() []byte {
return append(s.X.Bytes(), s.Y.Bytes()...)
}

// New creates a new Wallet backed by a ECC key pair. Uses system entropy.
func newWallet() (*Wallet, error) {
k, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
return nil, err
}
pk := Wallet(k.PublicKey)
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
}

0 comments on commit 8969bc4

Please sign in to comment.