diff --git a/blackstar.go b/app/app.go similarity index 84% rename from blackstar.go rename to app/app.go index f7183cfdc2..2e23dc37bb 100644 --- a/blackstar.go +++ b/app/app.go @@ -1,4 +1,4 @@ -package blackstar +package app import ( "github.com/tendermint/blackstar/types" @@ -25,18 +25,13 @@ func (app *Blackstar) Info() string { return "Blackstar v" + version } -type SetAccount struct { - PubKey crypto.PubKey - Account types.Account -} - func (app *Blackstar) SetOption(key string, value string) (log string) { if key == "setAccount" { var err error - var setAccount SetAccount + var setAccount types.PubAccount wire.ReadJSONPtr(&setAccount, []byte(value), &err) if err != nil { - return "Error decoding SetAccount message: " + err.Error() + return "Error decoding setAccount message: " + err.Error() } pubKeyBytes := wire.BinaryBytes(setAccount.PubKey) accBytes := wire.BinaryBytes(setAccount.Account) @@ -225,8 +220,8 @@ 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.Account) (accs []types.Account, code tmsp.CodeType, errStr string) { - accs = make([]types.Account, 0, len(tx.Inputs)+len(tx.Outputs)) +func execTx(tx types.Tx, accMap map[string]types.PubAccount) (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 { var acc, ok = accMap[input.PubKey.KeyString()] @@ -249,9 +244,11 @@ func execTx(tx types.Tx, accMap map[string]types.Account) (accs []types.Account, var acc, ok = accMap[output.PubKey.KeyString()] if !ok { // Create new account if it doesn't already exist. - acc = types.Account{ - PubKey: output.PubKey, - Balance: output.Amount, + acc = types.PubAccount{ + PubKey: output.PubKey, + Account: types.Account{ + Balance: output.Amount, + }, } accMap[output.PubKey.KeyString()] = acc continue @@ -268,9 +265,34 @@ func execTx(tx types.Tx, accMap map[string]types.Account) (accs []types.Account, //---------------------------------------- -func loadAccounts(eyesCli *eyes.MerkleEyesClient, pubKeys []crypto.PubKey) map[string]types.Account { - return nil +func loadAccounts(eyesCli *eyes.MerkleEyesClient, pubKeys []crypto.PubKey) (accMap map[string]types.PubAccount) { + accMap = make(map[string]types.PubAccount, len(pubKeys)) + for _, pubKey := range pubKeys { + keyString := pubKey.KeyString() + accBytes, err := eyesCli.GetSync([]byte(keyString)) + if err != nil { + panic("Error loading account: " + err.Error()) + } + var acc types.PubAccount + err = wire.ReadBinaryBytes(accBytes, &acc) + if err != nil { + panic("Error reading account: " + err.Error()) + } + acc.PubKey = pubKey // Set volatile field + accMap[keyString] = acc + } + return } -func storeAccounts(eyesCli *eyes.MerkleEyesClient, accs []types.Account) { +// NOTE: accs must be stored in deterministic order. +func storeAccounts(eyesCli *eyes.MerkleEyesClient, accs []types.PubAccount) { + for _, acc := range accs { + accBytes := wire.BinaryBytes(acc.Account) + err := eyesCli.SetSync([]byte(acc.PubKey.KeyString()), accBytes) + if err != nil { + panic("Error storing account: " + err.Error()) + } + } } + +//---------------------------------------- diff --git a/genesis.json b/genesis.json new file mode 100644 index 0000000000..a810af0a7c --- /dev/null +++ b/genesis.json @@ -0,0 +1,6 @@ +{"Accounts":[ + { + "PubKey":[1,"31F4BF201D3606E33707B098B1EEA7D03A4BB9E9795F0116ED1A038D7B5A6BDE"], + "Account":{"Sequence":0,"Balance":2100000000000000} + } +]} diff --git a/main.go b/main.go new file mode 100644 index 0000000000..ffd1c50df4 --- /dev/null +++ b/main.go @@ -0,0 +1,62 @@ +package main + +import ( + "flag" + "fmt" + + "github.com/tendermint/blackstar/app" + "github.com/tendermint/blackstar/types" + . "github.com/tendermint/go-common" + "github.com/tendermint/go-wire" + eyes "github.com/tendermint/merkleeyes/client" + "github.com/tendermint/tmsp/server" +) + +func main() { + + addrPtr := flag.String("address", "tcp://0.0.0.0:46658", "Listen address") + eyesPtr := flag.String("eyes", "tcp://0.0.0.0:46659", "MerkleEyes address") + genPtr := flag.String("genesis", "genesis.json", "Genesis JSON file") + flag.Parse() + + // Connect to MerkleEyes + eyesCli, err := eyes.NewMerkleEyesClient(*eyesPtr) + if err != nil { + Exit("connect to MerkleEyes: " + err.Error()) + } + + // Create BlackStar app + app := app.NewBlackstar(eyesCli) + + // Load GenesisState + jsonBytes, err := ReadFile(*genPtr) + if err != nil { + Exit("read genesis: " + err.Error()) + } + genesisState := types.GenesisState{} + wire.ReadJSONPtr(&genesisState, jsonBytes, &err) + if err != nil { + Exit("parsing genesis JSON: " + err.Error()) + } + for _, account := range genesisState.Accounts { + pubKeyBytes := wire.BinaryBytes(account.PubKey) + accBytes := wire.BinaryBytes(account.Account) + err = eyesCli.SetSync(pubKeyBytes, accBytes) + if err != nil { + Exit("loading genesis accounts: " + err.Error()) + } + fmt.Println("Loaded ", account) + } + + // Start the listener + _, err = server.StartListener(*addrPtr, app) + if err != nil { + Exit("create listener: " + err.Error()) + } + + // Wait forever + TrapSignal(func() { + // Cleanup + }) + +} diff --git a/tests/common.go b/tests/common.go new file mode 100644 index 0000000000..d231538fd3 --- /dev/null +++ b/tests/common.go @@ -0,0 +1,47 @@ +package tests + +import ( + "github.com/tendermint/blackstar/types" + . "github.com/tendermint/go-common" + "github.com/tendermint/go-crypto" +) + +// Creates a PrivAccount from secret. +// The amount is not set. +func PrivAccountFromSecret(secret string) types.PrivAccount { + privKey := crypto.GenPrivKeyEd25519FromSecret(secret) + privAccount := types.PrivAccount{ + PrivKey: privKey, + PubKey: privKey.PubKey(), + Account: types.Account{ + Sequence: 0, + Balance: 0, + }, + } + return privAccount +} + +// Make `num` random accounts +func RandAccounts(num int, minAmount uint64, maxAmount uint64) []types.PrivAccount { + privAccs := make([]types.PrivAccount, num) + for i := 0; i < num; i++ { + + balance := minAmount + if maxAmount > minAmount { + balance += RandUint64() % (maxAmount - minAmount) + } + + privKey := crypto.GenPrivKeyEd25519() + pubKey := privKey.PubKey() + privAccs[i] = types.PrivAccount{ + PrivKey: privKey, + PubKey: pubKey, + Account: types.Account{ + Sequence: 0, + Balance: balance, + }, + } + } + + return privAccs +} diff --git a/tests/tendermint/.main.go.swp b/tests/tendermint/.main.go.swp new file mode 100644 index 0000000000..1ced650666 Binary files /dev/null and b/tests/tendermint/.main.go.swp differ diff --git a/tests/tendermint/main.go b/tests/tendermint/main.go new file mode 100644 index 0000000000..34cc2f45e6 --- /dev/null +++ b/tests/tendermint/main.go @@ -0,0 +1,96 @@ +package main + +import ( + "encoding/hex" + "fmt" + + "github.com/gorilla/websocket" + "github.com/tendermint/blackstar/tests" + "github.com/tendermint/blackstar/types" + . "github.com/tendermint/go-common" + "github.com/tendermint/go-rpc/client" + "github.com/tendermint/go-rpc/types" + "github.com/tendermint/go-wire" + _ "github.com/tendermint/tendermint/rpc/core/types" // Register RPCResponse > Result types +) + +func main() { + ws := rpcclient.NewWSClient("ws://127.0.0.1:46657/websocket") + // ws := rpcclient.NewWSClient("ws://104.236.69.128:46657/websocket") + _, err := ws.Start() + if err != nil { + Exit(err.Error()) + } + + // Read a bunch of responses + go func() { + for { + res, ok := <-ws.ResultsCh + if !ok { + break + } + fmt.Println("res:", Blue(string(res))) + } + }() + + // Get the root account + root := tests.PrivAccountFromSecret("root") + sequence := uint(0) + // Make a bunch of PrivAccounts + privAccounts := tests.RandAccounts(1000, 1000000, 0) + + // Send coins to each account + for i := 0; i < len(privAccounts); i++ { + privAccount := privAccounts[i] + tx := types.Tx{ + Inputs: []types.Input{ + types.Input{ + PubKey: root.PubKey, + Amount: 1000002, + Sequence: sequence, + }, + }, + Outputs: []types.Output{ + types.Output{ + PubKey: privAccount.PubKey, + Amount: 1000000, + }, + }, + } + sequence += 1 + + // Write request + txBytes := wire.BinaryBytes(tx) + fmt.Println("tx:", hex.EncodeToString(txBytes)) + request := rpctypes.NewRPCRequest("fakeid", "broadcast_tx", Arr(txBytes)) + reqBytes := wire.JSONBytes(request) + fmt.Println("req:", hex.EncodeToString(reqBytes)) + //fmt.Print(".") + err := ws.WriteMessage(websocket.TextMessage, reqBytes) + if err != nil { + Exit("writing websocket request: " + err.Error()) + } + } + + /* + // 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) + } + */ + + ws.Stop() +} diff --git a/types/types.go b/types/types.go index 1011a550d2..15d04b745e 100644 --- a/types/types.go +++ b/types/types.go @@ -24,7 +24,19 @@ type Output struct { type Account struct { Sequence uint Balance uint64 - - // For convenience - crypto.PubKey `json:"-"` +} + +type PubAccount struct { + crypto.PubKey + Account +} + +type PrivAccount struct { + crypto.PubKey + crypto.PrivKey + Account +} + +type GenesisState struct { + Accounts []PubAccount }