diff --git a/Makefile b/Makefile index eda1cbdca..93a8cda75 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,6 @@ .PHONY: all test get_deps -all: protoc test install - -protoc: - protoc --go_out=. types/*.proto +all: test install install: get_deps go install github.com/tendermint/blackstar/cmd/... diff --git a/app/app.go b/app/app.go index d7baf056e..d94b89167 100644 --- a/app/app.go +++ b/app/app.go @@ -1,6 +1,7 @@ package app import ( + "fmt" "github.com/tendermint/blackstar/types" "github.com/tendermint/go-crypto" "github.com/tendermint/go-wire" @@ -62,7 +63,7 @@ func (app *Blackstar) AppendTx(txBytes []byte) (code tmsp.CodeType, result []byt // Load accounts accMap := loadAccounts(app.eyesCli, allPubKeys(tx)) // Execute tx - accs, code, errStr := execTx(tx, accMap) + accs, code, errStr := execTx(tx, accMap, false) if errStr != "" { return code, nil, "Error executing tx: " + errStr } @@ -89,7 +90,7 @@ func (app *Blackstar) CheckTx(txBytes []byte) (code tmsp.CodeType, result []byte // Load accounts accMap := loadAccounts(app.eyesCli, allPubKeys(tx)) // Execute tx - _, code, errStr = execTx(tx, accMap) + _, code, errStr = execTx(tx, accMap, false) if errStr != "" { return code, nil, "Error (mock) executing tx: " + errStr } @@ -225,7 +226,9 @@ func allPubKeys(tx types.Tx) (pubKeys []crypto.PubKey) { } // Returns accounts in order of types.Tx inputs and outputs -func execTx(tx types.Tx, accMap map[string]types.PubAccount) (accs []types.PubAccount, code tmsp.CodeType, errStr string) { +// appendTx: true if this is for AppendTx. +// TODO: create more intelligent sequence-checking. Current impl is just for a throughput demo. +func execTx(tx types.Tx, accMap map[string]types.PubAccount, appendTx bool) (accs []types.PubAccount, code tmsp.CodeType, errStr string) { accs = make([]types.PubAccount, 0, len(tx.Inputs)+len(tx.Outputs)) // Deduct from inputs for _, input := range tx.Inputs { @@ -233,8 +236,14 @@ func execTx(tx types.Tx, accMap map[string]types.PubAccount) (accs []types.PubAc if !ok { return nil, tmsp.CodeType_UnknownAccount, "Input account does not exist" } - if acc.Sequence != input.Sequence { - return nil, tmsp.CodeType_BadNonce, "Invalid sequence" + if appendTx { + if acc.Sequence != input.Sequence { + return nil, tmsp.CodeType_BadNonce, "Invalid sequence" + } + } else { + if acc.Sequence > input.Sequence { + return nil, tmsp.CodeType_BadNonce, "Invalid sequence (too low)" + } } if acc.Balance < input.Amount { return nil, tmsp.CodeType_InsufficientFunds, "Insufficient funds" @@ -256,14 +265,15 @@ func execTx(tx types.Tx, accMap map[string]types.PubAccount) (accs []types.PubAc }, } accMap[output.PubKey.KeyString()] = acc - continue + accs = append(accs, acc) + } else { + // Good! + if (acc.Balance + output.Amount) < acc.Balance { + return nil, tmsp.CodeType_InternalError, "Output balance overflow in execTx" + } + acc.Balance += output.Amount + accs = append(accs, acc) } - // Good! - if (acc.Balance + output.Amount) < acc.Balance { - return nil, tmsp.CodeType_InternalError, "Output balance overflow in execTx" - } - acc.Balance += output.Amount - accs = append(accs, acc) } return accs, tmsp.CodeType_OK, "" } @@ -296,6 +306,7 @@ func loadAccounts(eyesCli *eyes.MerkleEyesClient, pubKeys []crypto.PubKey) (accM // NOTE: accs must be stored in deterministic order. func storeAccounts(eyesCli *eyes.MerkleEyesClient, accs []types.PubAccount) { + fmt.Println("STORE ACCOUNTS", accs) for _, acc := range accs { accBytes := wire.BinaryBytes(acc.Account) err := eyesCli.SetSync([]byte(acc.PubKey.KeyString()), accBytes) diff --git a/tests/tendermint/main.go b/tests/tendermint/main.go index 81d595f07..c90827702 100644 --- a/tests/tendermint/main.go +++ b/tests/tendermint/main.go @@ -1,7 +1,6 @@ package main import ( - "encoding/hex" "fmt" "github.com/gorilla/websocket" @@ -38,6 +37,7 @@ func main() { sequence := uint(0) // Make a bunch of PrivAccounts privAccounts := tests.RandAccounts(1000, 1000000, 0) + privAccountSequences := make(map[string]int) // Send coins to each account for i := 0; i < len(privAccounts); i++ { @@ -76,25 +76,51 @@ func main() { } } - /* - // Make a bunch of requests - for i := 0; ; i++ { - binary.BigEndian.PutUint64(buf, uint64(i)) - //txBytes := hex.EncodeToString(buf[:n]) - request := rpctypes.NewRPCRequest("fakeid", "broadcast_tx", Arr(buf[:8])) - reqBytes := wire.JSONBytes(request) - //fmt.Println("!!", string(reqBytes)) - fmt.Print(".") - err := ws.WriteMessage(websocket.TextMessage, reqBytes) - if err != nil { - Exit(err.Error()) - } - if i%1000 == 0 { - fmt.Println(i) - } - time.Sleep(time.Microsecond * 1000) + // Now send coins between these accounts + for { + randA := RandInt() % len(privAccounts) + randB := RandInt() % len(privAccounts) + if randA == randB { + continue } - */ + + privAccountA := privAccounts[randA] + privAccountASequence := privAccountSequences[privAccountA.PubKey.KeyString()] + privAccountSequences[privAccountA.PubKey.KeyString()] = privAccountASequence + 1 + privAccountB := privAccounts[randB] + + tx := types.Tx{ + Inputs: []types.Input{ + types.Input{ + PubKey: privAccountA.PubKey, + Amount: 3, + Sequence: uint(privAccountASequence), + }, + }, + Outputs: []types.Output{ + types.Output{ + PubKey: privAccountB.PubKey, + Amount: 1, + }, + }, + } + + // Sign request + signBytes := wire.BinaryBytes(tx) + sig := privAccountA.PrivKey.Sign(signBytes) + tx.Inputs[0].Signature = sig + //fmt.Println("tx:", tx) + + // Write request + txBytes := wire.BinaryBytes(tx) + request := rpctypes.NewRPCRequest("fakeid", "broadcast_tx_sync", Arr(txBytes)) + reqBytes := wire.JSONBytes(request) + //fmt.Print(".") + err := ws.WriteMessage(websocket.TextMessage, reqBytes) + if err != nil { + Exit("writing websocket request: " + err.Error()) + } + } ws.Stop() }