Relaxed nonce-checking for demo

This commit is contained in:
Jae Kwon 2016-02-08 15:01:26 -08:00
parent 7dccf61484
commit 538f3110b1
3 changed files with 69 additions and 35 deletions

View File

@ -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/...

View File

@ -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)

View File

@ -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()
}