Skip to content

Commit

Permalink
Merge pull request #127 from ubclaunchpad/126-allow-multiple-inputs-i…
Browse files Browse the repository at this point in the history
…n-transactions

Pluralized Transaction Inputs
  • Loading branch information
chadlagore committed Aug 26, 2017
2 parents 6dc8be0 + 4587504 commit 27747c5
Show file tree
Hide file tree
Showing 18 changed files with 569 additions and 299 deletions.
6 changes: 3 additions & 3 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,8 @@ func (a *App) HandleTransaction(txn *blockchain.Transaction) {
a.Chain.RLock()
defer a.Chain.RUnlock()

validTransaction := a.Pool.Push(txn, a.Chain)
if validTransaction {
code := a.Pool.Push(txn, a.Chain)
if code == consensus.ValidTransaction {
log.Debug("Added transaction to pool from address: " + txn.Sender.Repr())
} else {
log.Debug("Bad transaction rejected from sender: " + txn.Sender.Repr())
Expand Down Expand Up @@ -477,7 +477,7 @@ func (a *App) makeBlockRequest(currentHead *blockchain.Block,

// handleBlockResponse receives a block or nil from the newBlockChan and attempts
// to validate it and add it to the blockchain, or it handles a protocol error
// from the errChan. Returns whether the blockchain was modified and wether we
// from the errChan. Returns whether the blockchain was modified and whether we
// received an UpToDate response.
func (a *App) handleBlockResponse(newBlockChan chan *blockchain.Block,
errChan chan *msg.ProtocolError) (changed bool, upToDate bool) {
Expand Down
39 changes: 30 additions & 9 deletions app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
)

func init() {
log.SetLevel(log.DebugLevel)
log.SetLevel(log.ErrorLevel)
}

func TestPushHandlerNewBlock(t *testing.T) {
Expand Down Expand Up @@ -141,7 +141,7 @@ func TestHandleValidBlock(t *testing.T) {
bc, blk := blockchain.NewValidTestChainAndBlock()
a.Chain = bc
a.HandleBlock(blk)
assert.Equal(t, blk, a.Chain.Blocks[2])
assert.Equal(t, blk, a.Chain.Blocks[3])

// TODO: Assert miner restarted.
// TODO: Assert pool appropriately emptied.
Expand Down Expand Up @@ -237,14 +237,24 @@ func TestHandleBlockResponse(t *testing.T) {
a := createNewTestApp()
newBlockChan := make(chan *blockchain.Block, 1)
errChan := make(chan *msg.ProtocolError, 1)
newBlockChan <- a.Chain.RollBack()

// Roll the last block off of the chain, add to channel.
lastBlock := a.Chain.RollBack()
assert.NotNil(t, lastBlock)
newBlockChan <- lastBlock

// Handle the block.
changed, upToDate := a.handleBlockResponse(newBlockChan, errChan)
assert.True(t, changed)
assert.False(t, upToDate)

// Add an on-chain block to the handler (this shouldn't change the chain).
newBlockChan <- a.Chain.Blocks[1]
changed, upToDate = a.handleBlockResponse(newBlockChan, errChan)
assert.False(t, changed)
assert.False(t, upToDate)

// More stuff happens.
errChan <- msg.NewProtocolError(msg.UpToDate, "")
changed, upToDate = a.handleBlockResponse(newBlockChan, errChan)
assert.False(t, changed)
Expand All @@ -253,19 +263,30 @@ func TestHandleBlockResponse(t *testing.T) {
changed, upToDate = a.handleBlockResponse(newBlockChan, errChan)
assert.True(t, changed)
assert.False(t, upToDate)
assert.Equal(t, len(a.Chain.Blocks), 1)
assert.Equal(t, len(a.Chain.Blocks), 2)
}

func TestHandleWork(t *testing.T) {
a := createNewTestApp()
go a.HandleWork()
a.blockQueue <- a.Chain.RollBack()
time.Sleep(time.Second)

// Roll the last block off of the chain, add to channel (expect it added back).
lastBlock := a.Chain.RollBack()
assert.Equal(t, len(a.Chain.Blocks), 2)
a.blockQueue <- lastBlock
time.Sleep(time.Millisecond * 50)
assert.Equal(t, len(a.Chain.Blocks), 3)

// Kill the worker.
a.quitChan <- true
a.blockQueue <- a.Chain.RollBack()
time.Sleep(time.Second)
assert.Equal(t, len(a.Chain.Blocks), 1)

// Roll the last block off of the chain, add to channel
// (expect it not to be added back).
lastBlock = a.Chain.RollBack()
assert.Equal(t, len(a.Chain.Blocks), 2)
a.blockQueue <- lastBlock
time.Sleep(time.Millisecond * 50)
assert.Equal(t, len(a.Chain.Blocks), 2)
}

func TestPay(t *testing.T) {
Expand Down
7 changes: 5 additions & 2 deletions app/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package app
import (
"errors"

"github.com/ubclaunchpad/cumulus/consensus"

"github.com/ubclaunchpad/cumulus/blockchain"
"github.com/ubclaunchpad/cumulus/msg"

Expand Down Expand Up @@ -41,7 +43,7 @@ func (a *App) Pay(to string, amount uint64) error {
tbody := blockchain.TxBody{
Sender: wallet.Public(),
// TODO: Collect inputs.
Input: blockchain.TxHashPointer{},
Inputs: []blockchain.TxHashPointer{},
Outputs: []blockchain.TxOutput{
blockchain.TxOutput{
Recipient: to,
Expand All @@ -59,7 +61,8 @@ func (a *App) Pay(to string, amount uint64) error {
}

// The transaction must be added to the pool.
if !pool.Push(txn, a.Chain) {
code := pool.Push(txn, a.Chain)
if code != consensus.ValidTransaction {
return errors.New("transaction validation failed")
}

Expand Down
2 changes: 1 addition & 1 deletion blockchain/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func (b *Block) Len() int {
}

// Marshal converts a Block to a byte slice.
func (b *Block) Marshal() []byte {
func (b Block) Marshal() []byte {
var buf []byte
buf = append(buf, b.BlockHeader.Marshal()...)
for _, t := range b.Transactions {
Expand Down
29 changes: 22 additions & 7 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,32 @@ func (bc *BlockChain) LastBlock() *Block {
return bc.Blocks[len(bc.Blocks)-1]
}

// 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)) {
// GetInputTransaction returns the input Transaction referenced by TxHashPointer.
// If the Transaction does not exist, then GetInputTransaction returns nil.
func (bc *BlockChain) GetInputTransaction(t *TxHashPointer) *Transaction {
if t.BlockNumber > uint32(len(bc.Blocks)) {
return nil
}
b := bc.Blocks[t.Input.BlockNumber]
if t.Input.Index > uint32(len(b.Transactions)) {
b := bc.Blocks[t.BlockNumber]
if t.Index > uint32(len(b.Transactions)) {
return nil
}
return b.Transactions[t.Input.Index]
return b.Transactions[t.Index]
}

// GetAllInputs returns all the transactions referenced by a transaction
// as inputs. Returns an error if any of the transactios requested could
// not be found.
func (bc *BlockChain) GetAllInputs(t *Transaction) ([]*Transaction, error) {
txns := []*Transaction{}
for _, tx := range t.Inputs {
nextTxn := bc.GetInputTransaction(&tx)
if nextTxn == nil {
return nil, errors.New("input transaction not found")
}
txns = append(txns, nextTxn)
}
return txns, nil
}

// ContainsTransaction returns true if the BlockChain contains the transaction
Expand Down
13 changes: 7 additions & 6 deletions blockchain/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ func Genesis(miner Address, target Hash, blockReward uint64, extraData []byte) *
Amount: blockReward,
Recipient: miner.Repr(),
}
cbInput := TxHashPointer{
BlockNumber: 0,
Hash: NilHash,
Index: 0,
}

cbTx := &Transaction{
TxBody: TxBody{
Sender: NilAddr,
Input: TxHashPointer{
BlockNumber: 0,
Hash: NilHash,
Index: 0,
},
Sender: NilAddr,
Inputs: []TxHashPointer{cbInput},
Outputs: []TxOutput{cbReward},
},
Sig: NilSig,
Expand Down
Loading

0 comments on commit 27747c5

Please sign in to comment.