Skip to content

Commit

Permalink
Merge branch 'dev' into 111-missed-blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
bfbachmann committed Aug 13, 2017
2 parents c26ae6a + 25241c2 commit 72c93e2
Show file tree
Hide file tree
Showing 15 changed files with 303 additions and 67 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ run-console: cumulus
deps:
glide install

clean:
clean: cumulus
rm cumulus

install-glide:
Expand Down
15 changes: 15 additions & 0 deletions app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,18 @@ func TestHandleWork(t *testing.T) {
time.Sleep(time.Second)
assert.Equal(t, len(a.Chain.Blocks), 1)
}

func TestPay(t *testing.T) {
amt := uint64(5)
a := createNewTestApp()
err := a.Pay("badf00d", amt)

// Fail with low balance.
assert.NotNil(t, err)

a.CurrentUser.Wallet.SetBalance(amt)
err = a.Pay("badf00d", amt)

// Fail with bad inputs.
assert.NotNil(t, err)
}
65 changes: 40 additions & 25 deletions app/console.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,9 @@ func create(ctx *ishell.Context, app *App) {
"Transaction",
}, "What would you like to create?")
if choice == 0 {
createHotWallet(ctx, app)
createWallet(ctx, app)
} else {
shell.Print("Sender wallet ID: ")
senderID := shell.ReadLine()
shell.Print("Recipient wallet ID: ")
recipientID := shell.ReadLine()
shell.Print("Amount to send: ")
amount, err := strconv.ParseFloat(shell.ReadLine(), 64)
if err != nil {
shell.Println("Invalid number format. Please enter an amount in decimal format.")
return
}

// TODO: make transaction, add it to the pool, broadcast it
ctx.Printf(`\nNew Transaction: \nSenderID: %s \nRecipiendID: %s\nAmount: %f"`,
senderID, recipientID, amount)
createTransaction(ctx, app)
}
}

Expand Down Expand Up @@ -127,16 +114,6 @@ func connect(ctx *ishell.Context, a *App) {
}
}

func createHotWallet(ctx *ishell.Context, app *App) {
shell.Print("Enter wallet name: ")
name := shell.ReadLine()
wallet := blockchain.NewWallet()
app.CurrentUser.Wallet = wallet
app.CurrentUser.Name = name
emoji.Println(":credit_card: New wallet created!")
emoji.Println(":mailbox: Address: " + wallet.Public().Repr())
}

func toggleMiner(ctx *ishell.Context, app *App) {
if len(ctx.Args) != 1 {
if miner.IsMining() {
Expand Down Expand Up @@ -167,3 +144,41 @@ func toggleMiner(ctx *ishell.Context, app *App) {
shell.Println("Usage: miner [start] | [stop]")
}
}

func createWallet(ctx *ishell.Context, app *App) {
// Create a new wallet and set as CurrentUser's wallet.
wallet := blockchain.NewWallet()
app.CurrentUser.Wallet = *wallet
emoji.Println(":credit_card: New wallet created!")

// Give a printout of the address(es).
emoji.Print(":mailbox:")
ctx.Println(" Address: " + wallet.Public().Repr())
emoji.Println(":fist: Emoji Address: " + wallet.Public().Emoji())
ctx.Println("")
}

func createTransaction(ctx *ishell.Context, app *App) {
// Read in the recipient address.
emoji.Print(":credit_card:")
ctx.Println(" Enter recipient wallet address")
toAddress := shell.ReadLine()

// Get amount from user.
emoji.Print(":dollar:")
ctx.Println(" Enter amount to send: ")
amount, err := strconv.ParseUint(shell.ReadLine(), 10, 64)
if err != nil {
emoji.Println(":disappointed: Invalid number format. Please enter an amount in decimal format.")
return
}

// Try to make a payment.
err = app.Pay(toAddress, amount)
if err != nil {
emoji.Println(":disappointed: Transaction failed!")
ctx.Println(err.Error())
} else {
emoji.Println(":mailbox_with_mail: Its in the mail!")
}
}
58 changes: 55 additions & 3 deletions app/user.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package app

import "github.com/ubclaunchpad/cumulus/blockchain"
import (
"errors"

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

crand "crypto/rand"
)

// User holds basic user information.
type User struct {
Expand All @@ -12,14 +19,59 @@ type User struct {
// NewUser creates a new user
func NewUser() *User {
return &User{
Wallet: blockchain.NewWallet(),
Wallet: *blockchain.NewWallet(),
BlockSize: blockchain.DefaultBlockSize,
}
}

// getCurrentUser gets the current user.
// getCurrentUser gets the current user function only used for app initalization.
func getCurrentUser() *User {
// TODO: Check for local user information on disk,
// If doesnt exist, create new user.
return NewUser()
}

// Pay pays an amount of coin to an address `to`.
func (a *App) Pay(to string, amount uint64) error {
// Four steps must occur.
wallet := a.CurrentUser.Wallet
pool := a.Pool

// A legitimate transaction must be built.
tbody := blockchain.TxBody{
Sender: wallet.Public(),
// TODO: Collect inputs.
Input: blockchain.TxHashPointer{},
Outputs: []blockchain.TxOutput{
blockchain.TxOutput{
Recipient: to,
Amount: amount,
},
},
}

// The transaction must be signed.
if txn, err := tbody.Sign(a.CurrentUser.Wallet, crand.Reader); err == nil {

// The transaction must be broadcasted to the peers.
if err := wallet.SetPending(txn); err != nil {
return err
}

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

// The transaction must be broadcasted to the network.
a.PeerStore.Broadcast(msg.Push{
ResourceType: msg.ResourceTransaction,
Resource: txn,
})

} else {
return err
}

return nil
}
2 changes: 1 addition & 1 deletion blockchain/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func Genesis(miner Address, target Hash, blockReward uint64, extraData []byte) *

cbReward := TxOutput{
Amount: blockReward,
Recipient: miner,
Recipient: miner.Repr(),
}

cbTx := &Transaction{
Expand Down
20 changes: 10 additions & 10 deletions blockchain/test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func NewTestTxHashPointer() TxHashPointer {
func NewTestTxOutput() TxOutput {
return TxOutput{
Amount: uint64(mrand.Int63()),
Recipient: NewWallet().Public(),
Recipient: NewWallet().Public().Repr(),
}
}

Expand All @@ -53,7 +53,7 @@ func NewTestTxBody() TxBody {
func NewTestTransaction() *Transaction {
sender := NewWallet()
tbody := NewTestTxBody()
t, _ := tbody.Sign(sender, crand.Reader)
t, _ := tbody.Sign(*sender, crand.Reader)
return t
}

Expand Down Expand Up @@ -124,7 +124,7 @@ func NewTestOutputBlock(t []*Transaction, input *Block) *Block {
}

// NewTestTransactionValue creates a new transaction with specific value a.
func NewTestTransactionValue(s, r Wallet, a uint64, i uint32) (*Transaction, error) {
func NewTestTransactionValue(s, r *Wallet, a uint64, i uint32) (*Transaction, error) {
tbody := TxBody{
Sender: s.Public(),
Input: TxHashPointer{
Expand All @@ -136,9 +136,9 @@ func NewTestTransactionValue(s, r Wallet, a uint64, i uint32) (*Transaction, err
}
tbody.Outputs[0] = TxOutput{
Amount: a,
Recipient: r.Public(),
Recipient: r.Public().Repr(),
}
return tbody.Sign(s, crand.Reader)
return tbody.Sign(*s, crand.Reader)
}

// NewValidBlockChainFixture creates a valid blockchain of two blocks.
Expand All @@ -150,13 +150,13 @@ func NewValidBlockChainFixture() (*BlockChain, Wallet) {
trA, _ := NewTestTransactionValue(original, sender, 2, 1)
trA.Outputs = append(trA.Outputs, TxOutput{
Amount: 2,
Recipient: sender.Public(),
Recipient: sender.Public().Repr(),
})

trB, _ := NewTestTransactionValue(sender, recipient, 4, 1)
trB.Input.Hash = HashSum(trA)

trB, _ = trB.TxBody.Sign(sender, crand.Reader)
trB, _ = trB.TxBody.Sign(*sender, crand.Reader)

cbA, _ := NewValidCloudBaseTestTransaction()
cbB, _ := NewValidCloudBaseTestTransaction()
Expand All @@ -169,7 +169,7 @@ func NewValidBlockChainFixture() (*BlockChain, Wallet) {
return &BlockChain{
Blocks: []*Block{inputBlock, outputBlock},
Head: NewTestHash(),
}, recipient
}, *recipient
}

// NewValidTestChainAndBlock creates a valid BlockChain and a Block that is valid
Expand All @@ -192,7 +192,7 @@ func NewValidTestChainAndBlock() (*BlockChain, *Block) {
}
tbody.Outputs[0] = TxOutput{
Amount: a,
Recipient: NewWallet().Public(),
Recipient: NewWallet().Public().Repr(),
}

tr, _ := tbody.Sign(s, crand.Reader)
Expand Down Expand Up @@ -223,7 +223,7 @@ func NewValidCloudBaseTestTransaction() (*Transaction, Address) {
}
cbReward := TxOutput{
Amount: 25,
Recipient: w.Public(),
Recipient: w.Public().Repr(),
}
cbTxBody := TxBody{
Sender: NilAddr,
Expand Down
13 changes: 11 additions & 2 deletions blockchain/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ func (thp TxHashPointer) Marshal() []byte {
// TxOutput defines an output to a transaction
type TxOutput struct {
Amount uint64
Recipient Address
Recipient string
}

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

Expand Down Expand Up @@ -103,3 +103,12 @@ func (t *Transaction) InputsEqualOutputs(other ...*Transaction) bool {

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

// GetTotalOutput sums the output amounts from the transaction.
func (t *Transaction) GetTotalOutput() uint64 {
result := uint64(0)
for _, out := range t.Outputs {
result += out.Amount
}
return result
}
23 changes: 16 additions & 7 deletions blockchain/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,38 @@ package blockchain

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestTxBodyLen(t *testing.T) {
txBody := NewTestTxBody()
senderLen := AddrLen
inputLen := 2*(32/8) + HashLen
outputLen := len(txBody.Outputs) * (64/8 + AddrLen)
outputLen := len(txBody.Outputs) * (64/8 + ReprLen)
txBodyLen := senderLen + inputLen + outputLen

if txBody.Len() != txBodyLen {
t.Fail()
}
assert.Equal(t, txBody.Len(), txBodyLen)
}

func TestTransactionLen(t *testing.T) {
tx := NewTestTransaction()
senderLen := AddrLen
inputLen := 2*(32/8) + HashLen
outputLen := len(tx.TxBody.Outputs) * (64/8 + AddrLen)
outputLen := len(tx.TxBody.Outputs) * (64/8 + ReprLen)
txBodyLen := senderLen + inputLen + outputLen
txLen := txBodyLen + SigLen

if tx.Len() != txLen {
t.Fail()
assert.Equal(t, tx.Len(), txLen)
}

func TestTransactionGetTotalOutput(t *testing.T) {
tx := NewTestTransaction()
tx.Outputs = []TxOutput{
TxOutput{
Recipient: tx.Outputs[0].Recipient,
Amount: 5,
},
}
assert.Equal(t, tx.GetTotalOutput(), uint64(5))
}
Loading

0 comments on commit 72c93e2

Please sign in to comment.