Skip to content

Commit

Permalink
Merge branch 'dev' into 25-mining-proof-of-work
Browse files Browse the repository at this point in the history
  • Loading branch information
david-julien committed Jun 13, 2017
2 parents 9673713 + b120ac0 commit 0666a58
Show file tree
Hide file tree
Showing 16 changed files with 623 additions and 235 deletions.
8 changes: 4 additions & 4 deletions blockchain/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@ func DecodeBlock(r io.Reader) *Block {

// ContainsTransaction returns true and the transaction itself if the Block
// contains the transaction.
func (b *Block) ContainsTransaction(t *Transaction) (bool, *Transaction) {
for _, tr := range b.Transactions {
func (b *Block) ContainsTransaction(t *Transaction) (bool, uint32) {
for i, tr := range b.Transactions {
if HashSum(t) == HashSum(tr) {
return true, tr
return true, uint32(i)
}
}
return false, nil
return false, 0
}
8 changes: 8 additions & 0 deletions blockchain/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,11 @@ func TestEncodeDecodeBlock(t *testing.T) {
t.Fail()
}
}

func TestContainsTransaction(t *testing.T) {
b := newBlock()

if exists, _ := b.ContainsTransaction(b.Transactions[0]); !exists {
t.Fail()
}
}
94 changes: 23 additions & 71 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package blockchain

import (
"crypto/ecdsa"
"encoding/gob"
"io"
)
Expand Down Expand Up @@ -42,81 +41,34 @@ func DecodeBlockChain(r io.Reader) *BlockChain {
return &bc
}

// ValidTransaction checks whether a transaction is valid, assuming the
// blockchain is valid.
func (bc *BlockChain) ValidTransaction(t *Transaction) bool {

// Find the transaction input in the chain (by hash)
var input *Transaction
inputBlock := bc.Blocks[t.Input.BlockNumber]
for _, transaction := range inputBlock.Transactions {
if t.Input.Hash == HashSum(transaction) {
input = transaction
}
}
if input == nil {
return false
}

// Check that output to sender in input is equal to outputs in t
var inAmount uint64
for _, output := range input.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
}
// AppendBlock adds a block to the end of the block chain.
func (bc *BlockChain) AppendBlock(b *Block, miner Address) {
b.BlockNumber = uint32(len(bc.Blocks))
b.LastBlock = HashSum(bc.Blocks[b.BlockNumber-1])
b.Miner = miner
bc.Blocks = append(bc.Blocks, b)
}

// Verify signature of t
hash := HashSum(t.TxBody)
if !ecdsa.Verify(t.Sender.Key(), hash.Marshal(), t.Sig.R, t.Sig.S) {
return false
// GetInputTransaction returns the input Transaction to t. If the input does
// not exist, then GetInputTransaction returns nil.
func (bc *BlockChain) GetInputTransaction(t *Transaction) *Transaction {
if t.Input.BlockNumber > uint32(len(bc.Blocks)) {
return nil
}

// Test if identical transaction already exists in chain.
endChain := uint32(len(bc.Blocks))
for i := t.Input.BlockNumber; i < endChain; i++ {
if exists, _ := bc.Blocks[i].ContainsTransaction(t); exists {
return false
}
b := bc.Blocks[t.Input.BlockNumber]
if t.Input.Index > uint32(len(b.Transactions)) {
return nil
}

return true
return b.Transactions[t.Input.Index]
}

// ValidBlock checks whether a block is valid
func (bc *BlockChain) ValidBlock(b *Block) bool {
// Check that block number is one greater than last block
lastBlock := bc.Blocks[b.BlockNumber-1]
if lastBlock.BlockNumber != b.BlockNumber-1 {
return false
}

// Verify every Transaction in the block.
for _, t := range b.Transactions {
if !bc.ValidTransaction(t) {
return false
// ContainsTransaction returns true if the BlockChain contains the transaction
// in a block between start and stop as indexes.
func (bc *BlockChain) ContainsTransaction(t *Transaction, start, stop uint32) (bool, uint32, uint32) {
for i := start; i < stop; i++ {
if exists, j := bc.Blocks[i].ContainsTransaction(t); exists {
return true, i, j
}
}

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

return true
}

// AppendBlock adds a block to the end of the block chain.
func (bc *BlockChain) AppendBlock(b *Block, miner Address) {
b.BlockNumber = uint32(len(bc.Blocks))
b.LastBlock = HashSum(bc.Blocks[b.BlockNumber-1])
b.Miner = miner
bc.Blocks = append(bc.Blocks, b)
return false, 0, 0
}
95 changes: 0 additions & 95 deletions blockchain/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package blockchain

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

log "github.com/Sirupsen/logrus"
Expand All @@ -12,100 +11,6 @@ func TestMain(t *testing.T) {
log.SetLevel(log.DebugLevel)
}

func TestValidTransactionNotInBlock(t *testing.T) {
tr, _ := newTransactionValue(newWallet(), newWallet(), 1)
bc, _ := newValidBlockChainFixture()

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

func TestValidTransactionInputsFail(t *testing.T) {
// 2 + 2 = 5 ?
bc, _ := newValidBlockChainFixture()
tr := bc.Blocks[1].Transactions[0]
tr.Outputs[0].Amount = 5

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

func TestValidTransactionSignatureFail(t *testing.T) {
bc, _ := newValidBlockChainFixture()
tr := bc.Blocks[1].Transactions[0]

fakeSender := newWallet()
tr, _ = tr.TxBody.Sign(fakeSender, crand.Reader)
bc.Blocks[1].Transactions[0] = tr

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

func TestValidTransactionPass(t *testing.T) {
bc, b := newValidChainAndBlock()
tr := b.Transactions[0]

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

func TestTransactionRespend(t *testing.T) {
bc, _ := newValidBlockChainFixture()
trC := bc.Blocks[1].Transactions[0]
b := newOutputBlock([]*Transaction{trC}, bc.Blocks[1])
bc.AppendBlock(b, newWallet().Public())

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

func TestValidBlockTransactionInvalid(t *testing.T) {
bc, _ := newValidBlockChainFixture()
tr := bc.Blocks[1].Transactions[0]
tr.Outputs[0].Amount = 5

if bc.ValidBlock(bc.Blocks[1]) {
t.Fail()
}
}

func TestValidBlockNumberWrong(t *testing.T) {
bc, _ := newValidBlockChainFixture()
bc.Blocks[1].BlockNumber = 2

if bc.ValidBlock(bc.Blocks[1]) {
t.Fail()
}
}

func TestValidBlockHashWrong(t *testing.T) {
bc, b := newValidChainAndBlock()
b.BlockHeader.LastBlock = newHash()

if bc.ValidBlock(b) {
t.Fail()
}
}

func TestValidBlock(t *testing.T) {
bc, b := newValidChainAndBlock()

if !bc.ValidBlock(b) {
t.Fail()
}
}

func TestBlockTwoInputs(t *testing.T) {
// block should fail to be valid if there exists two transactions
// referencing the same input, but output > input (double spend attack)
}

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

Expand Down
9 changes: 6 additions & 3 deletions blockchain/test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func newTxHashPointer() TxHashPointer {
return TxHashPointer{
BlockNumber: mrand.Uint32(),
Hash: newHash(),
Index: mrand.Uint32(),
}
}

Expand Down Expand Up @@ -107,12 +108,13 @@ func newOutputBlock(t []*Transaction, input *Block) *Block {
}
}

func newTransactionValue(s, r Wallet, a uint64) (*Transaction, error) {
func newTransactionValue(s, r Wallet, a uint64, i uint32) (*Transaction, error) {
tbody := TxBody{
Sender: s.Public(),
Input: TxHashPointer{
BlockNumber: 0,
Hash: newHash(),
Index: i,
},
Outputs: make([]TxOutput, 1),
}
Expand All @@ -129,13 +131,13 @@ func newValidBlockChainFixture() (*BlockChain, Wallet) {
sender := newWallet()
recipient := newWallet()

trA, _ := newTransactionValue(original, sender, 2)
trA, _ := newTransactionValue(original, sender, 2, 1)
trA.Outputs = append(trA.Outputs, TxOutput{
Amount: 2,
Recipient: sender.Public(),
})

trB, _ := newTransactionValue(sender, recipient, 4)
trB, _ := newTransactionValue(sender, recipient, 4, 0)
trB.Input.Hash = HashSum(trA)

trB, _ = trB.TxBody.Sign(sender, crand.Reader)
Expand Down Expand Up @@ -166,6 +168,7 @@ func newValidChainAndBlock() (*BlockChain, *Block) {
Input: TxHashPointer{
BlockNumber: 1,
Hash: HashSum(inputTransaction),
Index: 0,
},
Outputs: make([]TxOutput, 1),
}
Expand Down
19 changes: 19 additions & 0 deletions blockchain/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const (
type TxHashPointer struct {
BlockNumber uint32
Hash Hash
Index uint32
}

// Marshal converts a TxHashPointer to a byte slice
Expand Down Expand Up @@ -88,3 +89,21 @@ func (t *Transaction) Marshal() []byte {
buf = append(buf, t.Sig.Marshal()...)
return buf
}

// InputsEqualOutputs returns true if t.Inputs == other.Outputs, as well
// as the difference between the two (outputs - inputs).
func (t *Transaction) InputsEqualOutputs(other ...*Transaction) bool {
var inAmount uint64
for _, otherTransaction := range other {
for _, output := range otherTransaction.Outputs {
inAmount += output.Amount
}
}

var outAmount uint64
for _, output := range t.Outputs {
outAmount += output.Amount
}

return (int(outAmount) - int(inAmount)) == 0
}
Loading

0 comments on commit 0666a58

Please sign in to comment.