Skip to content

Commit

Permalink
Merge 9ba1b5a into 793d893
Browse files Browse the repository at this point in the history
  • Loading branch information
chadlagore committed May 27, 2017
2 parents 793d893 + 9ba1b5a commit 7c67cee
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 23 deletions.
45 changes: 43 additions & 2 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package blockchain

import (
"crypto/ecdsa"
"encoding/gob"
"fmt"
"io"
)

Expand Down Expand Up @@ -41,12 +43,41 @@ func DecodeBlockChain(r io.Reader) *BlockChain {
return &bc
}

// ValidTransaction checks whether a transaction is valid, assuming the blockchain is valid.
// 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)
var I *Transaction
fmt.Println(t.Input.BlockNumber)
inputBlock := bc.Blocks[t.Input.BlockNumber]
for _, transaction := range inputBlock.Transactions {
if transaction.Input.Hash == t.Input.Hash {
I = transaction
}
}
if I == nil {
return false
}

// Check that output to sender in I is equal to outputs in T
var inAmount uint64
for _, output := range I.Outputs {
if output.Recipient == t.Sender {
inAmount += output.Amount
}
}
var outAmount uint64
for _, output := range t.Outputs {
outAmount += output.Amount
}
if inAmount != outAmount {
return false
}

// Verify signature of T
return false
ecdsa.Verify(t.Sender.Key(), t.Sig.Marshal(), t.Sig.R, t.Sig.S)
return true
}

// ValidBlock checks whether a block is valid
Expand All @@ -56,7 +87,17 @@ func (bc *BlockChain) ValidBlock(b *Block) bool {
return false
}
}

// Check that block number is one greater than last block
lastBlock := bc.Blocks[b.BlockNumber-1]
if lastBlock.BlockNumber != b.BlockNumber-1 {
return false
}

// Check that hash of last block is correct
if HashSum(lastBlock) != b.LastBlock {
return false
}

return false
}
78 changes: 78 additions & 0 deletions blockchain/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,87 @@ package blockchain

import (
"bytes"
crand "crypto/rand"
"testing"

log "github.com/Sirupsen/logrus"
)

// TestMain sets logging levels for tests.
func TestMain(t *testing.T) {
log.SetLevel(log.DebugLevel)
}

func TestValidTransactionNotInBlock(t *testing.T) {
tr := newTransactionValue(5, newWallet().Public())

inputTransactions := make([]*Transaction, 0)
outputTransactions := make([]*Transaction, 0)

inputBlock := newInputBlock(inputTransactions)
outputBlock := newOutputBlock(outputTransactions, inputBlock)

bc := BlockChain{
Blocks: []*Block{inputBlock, outputBlock},
Head: newHash(),
}

if bc.ValidTransaction(tr) {
t.Fail()
}
}

func TestValidTransactionInputsFail(t *testing.T) {
// 2 + 2 = 5 ?
trA := newTransactionValue(2, newWallet().Public())
trB := newTransactionValue(2, newWallet().Public())
trC := newTransactionValue(5, newWallet().Public())

inputTransactions := []*Transaction{trA, trB}
outputTransactions := []*Transaction{trC}

inputBlock := newInputBlock(inputTransactions)
outputBlock := newOutputBlock(outputTransactions, inputBlock)

bc := BlockChain{
Blocks: []*Block{inputBlock, outputBlock},
Head: newHash(),
}

if bc.ValidTransaction(trC) {
t.Fail()
}
}

func TestValidTransactionSignatureFail(t *testing.T) {
tr := newTransactionValue(2, newWallet().Public())

// Fake sender puts in a silly signature.
fakeSender := newWallet()
fakeTransaction := newTransaction()
digest := HashSum(fakeTransaction.TxBody)
tr.Sig, _ = fakeSender.Sign(digest, crand.Reader)

transactions := []*Transaction{tr}
b := newInputBlock(transactions)

bc := BlockChain{
Blocks: []*Block{b},
Head: newHash(),
}

if bc.ValidTransaction(tr) {
t.Fail()
}
}

// TestValidBlock tests the three cases in which a block can fail to be valid.
func TestValidBlock(t *testing.T) {
// b conains invalid transaction.
// Block number for b is not one greater than the last block.
// The hash of the last block is incorrect.
}

func TestEncodeDecodeBlockChain(t *testing.T) {
b1 := newBlockChain()

Expand Down
44 changes: 44 additions & 0 deletions blockchain/test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,47 @@ func newBlockChain() *BlockChain {
bc.Head = HashSum(bc.Blocks[nBlocks-1])
return &bc
}

func newInputBlock(t []*Transaction) *Block {
return &Block{
BlockHeader: BlockHeader{
BlockNumber: 0,
LastBlock: newHash(),
Miner: newWallet().Public(),
},
Transactions: t,
}
}

func newOutputBlock(t []*Transaction, input *Block) *Block {
return &Block{
BlockHeader: BlockHeader{
BlockNumber: input.BlockNumber + 1,
LastBlock: HashSum(input),
Miner: newWallet().Public(),
},
Transactions: t,
}
}

func newTransactionValue(a uint64, r Address) *Transaction {
sender := newWallet()
tbody := TxBody{
Sender: newWallet().Public(),
Input: TxHashPointer{
BlockNumber: 0,
Hash: newHash(),
},
Outputs: make([]TxOutput, 1),
}
tbody.Outputs[0] = TxOutput{
Amount: a,
Recipient: r,
}
digest := HashSum(tbody)
sig, _ := sender.Sign(digest, crand.Reader)
return &Transaction{
TxBody: tbody,
Sig: sig,
}
}
36 changes: 15 additions & 21 deletions blockchain/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,27 @@ var (
)

// Address represents a wallet that can be a recipient in a transaction.
type Address [AddrLen]byte
type Address struct {
X, Y *big.Int
}

// 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
}
buf = append(buf, a.X.Bytes()...)
buf = append(buf, a.Y.Bytes()...)
return buf
}

// Key returns the ECDSA public key representation of the address.
func (a Address) Key() *ecdsa.PublicKey {
return &ecdsa.PublicKey{
Curve: curve,
X: a.X,
Y: a.X,
}
}

// Wallet represents a wallet that we have the ability to sign for.
type Wallet interface {
Public() Address
Expand All @@ -53,23 +63,7 @@ func (w *wallet) key() *ecdsa.PrivateKey {

// 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
}
for i, b := range y {
addr[CoordLen+i] = b
}

return addr
return Address{X: w.PublicKey.X, Y: w.PublicKey.Y}
}

// Sign returns a signature of the digest.
Expand Down

0 comments on commit 7c67cee

Please sign in to comment.