Skip to content

Commit

Permalink
Merge ba4cb3b into 59bd054
Browse files Browse the repository at this point in the history
  • Loading branch information
jordanschalm committed May 15, 2017
2 parents 59bd054 + ba4cb3b commit 8cff372
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 68 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ glide install
## Testing

```
go test ./...
go test $(go list ./... | grep -v /vendor/)
```
47 changes: 34 additions & 13 deletions blockchain/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,69 @@ import (
"crypto/sha256"
"encoding/binary"
"encoding/gob"
"fmt"
"io"
)

const (
// BlockSize is the maximum size of a block in bytes when marshaled (about 250K).
BlockSize = 1 << 18
// BlockHeaderLen is the length in bytes of a block header.
BlockHeaderLen = 32/8 + HashLen + AddrLen
)

// BlockHeader contains metadata about a block
type BlockHeader struct {
blockNumber uint32
lastBlock Hash
miner Wallet
BlockNumber uint32
LastBlock Hash
Miner Address
}

// 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 := make([]byte, 4, BlockHeaderLen)
binary.LittleEndian.PutUint32(buf, bh.BlockNumber)
for _, b := range bh.LastBlock {
buf = append(buf, b)
}
buf = append(buf, bh.miner.Marshal()...)
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
}

// Len returns the length in bytes of the Block.
func (b *Block) Len() int {
l := BlockHeaderLen
for _, t := range b.Transactions {
l += t.Len()
}
return l
}

// Marshal converts a Block to a byte slice
// Marshal converts a Block to a byte slice.
func (b *Block) Marshal() []byte {
buf := b.BlockHeader.Marshal()
for _, t := range b.transactions {
buf := make([]byte, 0, b.Len())
buf = append(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)
err := gob.NewEncoder(w).Encode(b)
if err != nil {
fmt.Println(err.Error())
}
}

// Decode reads the marshalled block from the given io.Reader
// Decode reads the marshalled block from the given io.Reader and populates b
func (b *Block) Decode(r io.Reader) {
gob.NewDecoder(r).Decode(b)
}
Expand Down
20 changes: 16 additions & 4 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,25 @@ import (
"io"
)

// HashLen is the length in bytes of a hash.
const HashLen = 32

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

// Marshal converts a Hash to a slice.
func (h Hash) Marshal() []byte {
buf := make([]byte, HashLen)
for i, b := range h {
buf[i] = b
}
return buf
}

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

// Encode writes the marshalled blockchain to the given io.Writer
Expand All @@ -34,7 +46,7 @@ func (bc *BlockChain) ValidTransaction(t *Transaction) bool {

// ValidBlock checks whether a block is valid
func (bc *BlockChain) ValidBlock(b *Block) bool {
for _, t := range b.transactions {
for _, t := range b.Transactions {
if !bc.ValidTransaction(t) {
return false
}
Expand Down
64 changes: 43 additions & 21 deletions blockchain/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,85 @@ import (
"encoding/binary"
)

const (
// TxHashPointerLen is the length in bytes of a hash pointer.
TxHashPointerLen = 32/8 + HashLen
// TxOutputLen is the length in bytes of a transaction output.
TxOutputLen = 64/8 + AddrLen
)

// TxHashPointer is a reference to a transaction on the blockchain.
type TxHashPointer struct {
blockNumber uint32
hash Hash
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)
}
buf := make([]byte, 4, TxHashPointerLen)
binary.LittleEndian.PutUint32(buf, thp.BlockNumber)
buf = append(buf, thp.Hash.Marshal()...)
return buf
}

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

// 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()...)
buf := make([]byte, 8, TxOutputLen)
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
Sender Address
Input TxHashPointer
Outputs []TxOutput
}

// Len returns the length of a transaction body
func (tb TxBody) Len() int {
return AddrLen + TxHashPointerLen + len(tb.Outputs)*TxOutputLen
}

// 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 := make([]byte, 0, tb.Len())
buf = append(buf, tb.Sender.Marshal()...)
buf = append(buf, tb.Input.Marshal()...)
for _, out := range tb.Outputs {
buf = append(buf, out.Marshal()...)
}
return buf
}

// Hash computes the SHA256 hash of a transaction body.
func (tb TxBody) Hash() Hash {
return sha256.Sum256(tb.Marshal())
}

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

// Len returns the length in bytes of a transaction
func (t *Transaction) Len() int {
return t.TxBody.Len() + SigLen
}

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

Expand Down
104 changes: 75 additions & 29 deletions blockchain/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,95 @@ package blockchain
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"fmt"
"io"
"math/big"
)

// The curve we use for our ECC crypto.
var curve = elliptic.P256()
const (
// CoordLen is the length in bytes of coordinates with our ECC curve.
CoordLen = 32
// AddrLen is the length in bytes of addresses.
AddrLen = 2 * CoordLen
// SigLen is the length in bytes of signatures.
SigLen = AddrLen
)

// Wallet represents a Cumulus wallet address in the blockchain.
type Wallet ecdsa.PublicKey
var (
// The curve we use for our ECC crypto.
curve = elliptic.P256()
// NilSig is a signature representing a failed Sign operation
NilSig = Signature{big.NewInt(0), big.NewInt(0)}
// NilAddr is an address representing no address
NilAddr = Address{}
)

// Signature represents a signature of a transaction.
type Signature struct {
X big.Int
Y big.Int
// Address represents a wallet that can be a recipient in a transaction.
type Address [AddrLen]byte

// Marshal converts an Address to a byte slice.
func (a Address) Marshal() []byte {
buf := make([]byte, AddrLen)
for i, b := range a {
buf[i] = b
}
return buf
}

// Marshal converts a signature to a byte slice
func (s *Signature) Marshal() []byte {
return append(s.X.Bytes(), s.Y.Bytes()...)
// Wallet represents a wallet that we have the ability to sign for.
type Wallet interface {
Public() Address
Sign(digest Hash, random io.Reader) Signature
}

// 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
// Internal representation of a wallet.
type wallet ecdsa.PrivateKey

// Key retreives the underlying private key from a wallet.
func (w *wallet) key() *ecdsa.PrivateKey {
return (*ecdsa.PrivateKey)(w)
}

// Public returns the public key as byte array, or address, of the wallet.
func (w *wallet) Public() Address {
addr := Address{}
x := w.PublicKey.X.Bytes()
y := w.PublicKey.Y.Bytes()

if len(x) != CoordLen || len(y) != CoordLen {
// Invalid wallet
return NilAddr
}

for i, b := range x {
addr[i] = b
}
pk := Wallet(k.PublicKey)
return &pk, nil
for i, b := range y {
addr[CoordLen+i] = b
}

return addr
}

// String returns a human-readable string representation of a wallet
func (w *Wallet) String() string {
return fmt.Sprintf("%x-%x", w.X, w.Y)
// Sign returns a signature of the digest.
func (w *wallet) Sign(digest Hash, random io.Reader) Signature {
r, s, err := ecdsa.Sign(random, w.key(), digest.Marshal())
if err != nil {
// Signing failed
return NilSig
}
return Signature{r, s}
}

// Marshal converts the Wallet to a byte slice
func (w *Wallet) Marshal() []byte {
return elliptic.Marshal(curve, w.X, w.Y)
// Signature represents a signature of a transaction.
type Signature struct {
R *big.Int
S *big.Int
}

// 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
// Marshal converts a signature to a byte slice. Should be 64 bytes long.
func (s *Signature) Marshal() []byte {
buf := make([]byte, 0, SigLen)
buf = append(buf, s.R.Bytes()...)
buf = append(buf, s.S.Bytes()...)
return buf
}

0 comments on commit 8cff372

Please sign in to comment.