diff --git a/app/app.go b/app/app.go index 60e339561..87522f612 100644 --- a/app/app.go +++ b/app/app.go @@ -47,9 +47,9 @@ func (app *Basecoin) SetOption(key string, value string) (log string) { return "Error decoding setAccount message: " + err.Error() } accBytes := wire.BinaryBytes(setAccount) - err = app.eyesCli.SetSync(setAccount.PubKey.Address(), accBytes) - if err != nil { - return "Error saving account: " + err.Error() + res := app.eyesCli.SetSync(setAccount.PubKey.Address(), accBytes) + if res.IsErr() { + return "Error saving account: " + res.Error() } return "Success" } @@ -96,7 +96,6 @@ func (app *Basecoin) CheckTx(txBytes []byte) (res tmsp.Result) { // TMSP::Query func (app *Basecoin) Query(query []byte) (res tmsp.Result) { - return tmsp.OK res = app.eyesCli.GetSync(query) if res.IsErr() { return res.PrependLog("Error querying eyesCli") diff --git a/state/execution.go b/state/execution.go index c8b41a1f5..b86620f87 100644 --- a/state/execution.go +++ b/state/execution.go @@ -22,24 +22,24 @@ func ExecTx(state *State, tx types.Tx, isCheckTx bool, evc events.Fireable) tmsp // First, get inputs accounts, res := getInputs(state, tx.Inputs) if res.IsErr() { - return res + return res.PrependLog("in getInputs()") } // Then, get or make outputs. accounts, res = getOrMakeOutputs(state, accounts, tx.Outputs) if res.IsErr() { - return res + return res.PrependLog("in getOrMakeOutputs()") } // Validate inputs and outputs signBytes := tx.SignBytes(state.GetChainID()) inTotal, res := validateInputs(state, accounts, signBytes, tx.Inputs) if res.IsErr() { - return res + return res.PrependLog("in validateInputs()") } outTotal, res := validateOutputs(tx.Outputs) if res.IsErr() { - return res + return res.PrependLog("in validateOutputs()") } if outTotal > inTotal { return tmsp.ErrBaseInsufficientFunds @@ -73,8 +73,7 @@ func ExecTx(state *State, tx types.Tx, isCheckTx bool, evc events.Fireable) tmsp // First, get input account inAcc := state.GetAccount(tx.Input.Address) if inAcc == nil { - log.Info(Fmt("Can't find in account %X", tx.Input.Address)) - return tmsp.ErrBaseInvalidAddress + return tmsp.ErrBaseUnknownAddress } // Validate input @@ -87,7 +86,7 @@ func ExecTx(state *State, tx types.Tx, isCheckTx bool, evc events.Fireable) tmsp res := validateInput(state, inAcc, signBytes, tx.Input) if res.IsErr() { log.Info(Fmt("validateInput failed on %X: %v", tx.Input.Address, res)) - return res + return res.PrependLog("in validateInput()") } if tx.Input.Amount < tx.Fee { log.Info(Fmt("Sender did not send enough to cover the fee %X", tx.Input.Address)) @@ -98,7 +97,7 @@ func ExecTx(state *State, tx types.Tx, isCheckTx bool, evc events.Fireable) tmsp if strings.HasPrefix(string(tx.Address), "gov/") { // This is a gov call. } else { - return tmsp.ErrBaseInvalidAddress.AppendLog(Fmt("Unrecognized address %X", tx.Address)) + return tmsp.ErrBaseUnknownAddress.AppendLog(Fmt("Unrecognized address %X", tx.Address)) } // Good! @@ -109,13 +108,13 @@ func ExecTx(state *State, tx types.Tx, isCheckTx bool, evc events.Fireable) tmsp // If this is AppendTx, actually save accounts if !isCheckTx { - state.SetAccount(inAcc) + state.SetAccount(tx.Input.Address, inAcc) // NOTE: value is dangling. // XXX: don't just give it back inAcc.Balance += value // TODO: logic. // TODO: persist - // state.SetAccount(inAcc) + // state.SetAccount(tx.Input.Address, inAcc) log.Info("Successful execution") // Fire events /* @@ -152,7 +151,7 @@ func getInputs(state types.AccountGetter, ins []types.TxInput) (map[string]*type } acc := state.GetAccount(in.Address) if acc == nil { - return nil, tmsp.ErrBaseInvalidAddress + return nil, tmsp.ErrBaseUnknownAddress } // PubKey should be present in either "account" or "in" if res := checkInputPubKey(in.Address, acc, in); res.IsErr() { @@ -192,15 +191,18 @@ func getOrMakeOutputs(state types.AccountGetter, accounts map[string]*types.Acco func checkInputPubKey(address []byte, acc *types.Account, in types.TxInput) tmsp.Result { if acc.PubKey == nil { if in.PubKey == nil { - return tmsp.ErrBaseUnknownPubKey + return tmsp.ErrBaseUnknownPubKey.AppendLog("PubKey not present in either acc or input") } if !bytes.Equal(in.PubKey.Address(), address) { - return tmsp.ErrBaseInvalidPubKey + return tmsp.ErrBaseInvalidPubKey.AppendLog("Input PubKey address does not match address") } acc.PubKey = in.PubKey } else { if in.PubKey != nil { - return tmsp.ErrBaseInvalidPubKey + // NOTE: allow redundant pubkey. + if !bytes.Equal(in.PubKey.Address(), address) { + return tmsp.ErrBaseInvalidPubKey.AppendLog("Input PubKey address does not match address") + } } } return tmsp.OK @@ -240,7 +242,7 @@ func validateInput(state *State, acc *types.Account, signBytes []byte, in types. } // Check signatures if !acc.PubKey.VerifyBytes(signBytes, in.Signature) { - return tmsp.ErrBaseInvalidSignature + return tmsp.ErrBaseInvalidSignature.AppendLog(Fmt("SignBytes: %X", signBytes)) } return tmsp.OK } @@ -271,7 +273,7 @@ func adjustByInputs(state *State, accounts map[string]*types.Account, ins []type state.SetCheckAccount(in.Address, acc.Sequence, acc.Balance) if !isCheckTx { // NOTE: Must be set in deterministic order - state.SetAccount(acc) + state.SetAccount(in.Address, acc) } } } @@ -286,7 +288,7 @@ func adjustByOutputs(state *State, accounts map[string]*types.Account, outs []ty if !isCheckTx { state.SetCheckAccount(out.Address, acc.Sequence, acc.Balance) // NOTE: Must be set in deterministic order - state.SetAccount(acc) + state.SetAccount(out.Address, acc) } } } diff --git a/state/state.go b/state/state.go index 9d037a4f1..3d2794c79 100644 --- a/state/state.go +++ b/state/state.go @@ -79,9 +79,9 @@ func (s *State) GetAccount(addr []byte) *types.Account { return &acc } -func (s *State) SetAccount(acc *types.Account) { +func (s *State) SetAccount(address []byte, acc *types.Account) { accBytes := wire.BinaryBytes(acc) - res := s.eyesCli.SetSync(acc.PubKey.Address(), accBytes) + res := s.eyesCli.SetSync(address, accBytes) if res.IsErr() { panic("Error storing account: " + res.Error()) } diff --git a/tests/tmsp/main.go b/tests/tmsp/main.go new file mode 100644 index 000000000..71cdbc856 --- /dev/null +++ b/tests/tmsp/main.go @@ -0,0 +1,64 @@ +package main + +import ( + "fmt" + + "github.com/tendermint/basecoin/app" + "github.com/tendermint/basecoin/tests" + "github.com/tendermint/basecoin/types" + . "github.com/tendermint/go-common" + "github.com/tendermint/go-wire" + eyescli "github.com/tendermint/merkleeyes/client" + _ "github.com/tendermint/tendermint/rpc/core/types" // Register RPCResponse > Result types +) + +/* + Get the "test" account. + PrivKey: 019F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A0867D3B5EAF0C0BF6B5A602D359DAECC86A7A74053490EC37AE08E71360587C870 + PubKey: 0167D3B5EAF0C0BF6B5A602D359DAECC86A7A74053490EC37AE08E71360587C870 + Address: D9B727742AA29FA638DC63D70813C976014C4CE0 +*/ +func main() { + eyesCli := eyescli.NewLocalClient() + bcApp := app.NewBasecoin(eyesCli) + fmt.Println(bcApp.Info()) + + tPriv := tests.PrivAccountFromSecret("test") + tPriv2 := tests.PrivAccountFromSecret("test2") + + // Seed Basecoin with account + tAcc := tPriv.Account + tAcc.Balance = 1000 + bcApp.SetOption("chainID", "test_chain_id") + bcApp.SetOption("account", string(wire.JSONBytes(tAcc))) + + // Construct a SendTx signature + tx := &types.SendTx{ + Inputs: []types.TxInput{ + types.TxInput{ + Address: tPriv.Account.PubKey.Address(), + PubKey: tPriv.Account.PubKey, // TODO is this needed? + Amount: 1, + Sequence: 1, + }, + }, + Outputs: []types.TxOutput{ + types.TxOutput{ + Address: tPriv2.Account.PubKey.Address(), + Amount: 1, + }, + }, + } + + // Sign request + signBytes := tx.SignBytes("test_chain_id") + fmt.Printf("SIGNBYTES %X", signBytes) + sig := tPriv.PrivKey.Sign(signBytes) + tx.Inputs[0].Signature = sig + //fmt.Println("tx:", tx) + + // Write request + txBytes := wire.BinaryBytes(tx) + res := bcApp.AppendTx(txBytes) + fmt.Println(res) +} diff --git a/types/tx.go b/types/tx.go index ca9b67f22..d16aebd11 100644 --- a/types/tx.go +++ b/types/tx.go @@ -48,10 +48,10 @@ type TxInput struct { func (txIn TxInput) ValidateBasic() tmsp.Result { if len(txIn.Address) != 20 { - return tmsp.ErrBaseInvalidAddress + return tmsp.ErrBaseInvalidAddress.AppendLog("(in TxInput)") } if txIn.Amount == 0 { - return tmsp.ErrBaseInvalidAmount + return tmsp.ErrBaseInvalidAmount.AppendLog("(in TxInput)") } return tmsp.OK } @@ -74,10 +74,10 @@ type TxOutput struct { func (txOut TxOutput) ValidateBasic() tmsp.Result { if len(txOut.Address) != 20 { - return tmsp.ErrBaseInvalidAddress + return tmsp.ErrBaseInvalidAddress.AppendLog("(in TxOutput)") } if txOut.Amount == 0 { - return tmsp.ErrBaseInvalidAmount + return tmsp.ErrBaseInvalidAmount.AppendLog("(in TxOutput)") } return tmsp.OK }