diff --git a/account/pubkey.go b/account/pubkey.go index 84acb721..5c387454 100644 --- a/account/pubkey.go +++ b/account/pubkey.go @@ -13,12 +13,12 @@ import ( type PubKey interface { Address() []byte VerifyBytes(msg []byte, sig Signature) bool + TypeByte() byte } // Types of PubKey implementations const ( PubKeyTypeNil = byte(0x00) - PubKeyTypeUnknown = byte(0x01) // For pay-to-pubkey-hash txs. PubKeyTypeEd25519 = byte(0x02) ) diff --git a/binary/log.go b/binary/log.go index c2f6e58a..cc6c6372 100644 --- a/binary/log.go +++ b/binary/log.go @@ -12,6 +12,7 @@ func init() { log.SetHandler( log15.LvlFilterHandler( log15.LvlWarn, + //log15.LvlDebug, log15.StreamHandler(os.Stderr, log15.LogfmtFormat()), ), ) diff --git a/binary/reflect.go b/binary/reflect.go index c9d7eb2c..e2982ea0 100644 --- a/binary/reflect.go +++ b/binary/reflect.go @@ -63,7 +63,7 @@ func RegisterType(info *TypeInfo) *TypeInfo { typeInfos[ptrRt] = info // See if the type implements HasTypeByte - if rt.Implements(reflect.TypeOf((*HasTypeByte)(nil)).Elem()) { + if rt.Kind() != reflect.Interface && rt.Implements(reflect.TypeOf((*HasTypeByte)(nil)).Elem()) { zero := reflect.Zero(rt) typeByte := zero.Interface().(HasTypeByte).TypeByte() if info.HasTypeByte && info.TypeByte != typeByte { diff --git a/cmd/gen_account.go b/cmd/gen_account.go index 4dcb446f..fe830181 100644 --- a/cmd/gen_account.go +++ b/cmd/gen_account.go @@ -1,7 +1,7 @@ package main import ( - "encoding/base64" + "encoding/hex" "fmt" . "github.com/tendermint/tendermint/account" @@ -15,14 +15,10 @@ func gen_account() { privAccount := GenPrivAccount() fmt.Printf(`Generated account: -Account Public Key: %X - (base64) %v -Account Private Key: %X - (base64) %v +Account Public Key: %v +Account Private Key: %v `, - privAccount.PubKey, - base64.StdEncoding.EncodeToString(BinaryBytes(privAccount.PubKey)), - privAccount.PrivKey, - base64.StdEncoding.EncodeToString(BinaryBytes(privAccount.PrivKey))) - + hex.EncodeToString(BinaryBytes(privAccount.PubKey)), + hex.EncodeToString(BinaryBytes(privAccount.PrivKey)), + ) } diff --git a/cmd/gen_tx.go b/cmd/gen_tx.go new file mode 100644 index 00000000..cfc2e219 --- /dev/null +++ b/cmd/gen_tx.go @@ -0,0 +1,124 @@ +package main + +import ( + "bufio" + "bytes" + "encoding/hex" + "fmt" + "os" + "strconv" + + account_ "github.com/tendermint/tendermint/account" + binary "github.com/tendermint/tendermint/binary" + block_ "github.com/tendermint/tendermint/block" + . "github.com/tendermint/tendermint/common" + db_ "github.com/tendermint/tendermint/db" + state_ "github.com/tendermint/tendermint/state" +) + +func getString(prompt string) string { + reader := bufio.NewReader(os.Stdin) + fmt.Print(prompt) + input, _ := reader.ReadString('\n') + return input[:len(input)-1] +} + +func getByteSliceFromBase64(prompt string) []byte { + input := getString(prompt) + bytes, err := hex.DecodeString(input) + if err != nil { + Exit(Fmt("Not in hexadecimal format: %v\nError: %v\n", input, err)) + } + return bytes +} + +func getByteSliceFromHex(prompt string) []byte { + input := getString(prompt) + bytes, err := hex.DecodeString(input) + if err != nil { + Exit(Fmt("Not in hexadecimal format: %v\nError: %v\n", input, err)) + } + return bytes +} + +func getUint64(prompt string) uint64 { + input := getString(prompt) + i, err := strconv.Atoi(input) + if err != nil { + Exit(Fmt("Not a valid uint64 amount: %v\nError: %v\n", input, err)) + } + return uint64(i) +} + +func gen_tx() { + + // Get State, which may be nil. + stateDB := db_.GetDB("state") + state := state_.LoadState(stateDB) + + // Get source pubkey + srcPubKeyBytes := getByteSliceFromBase64("Enter source pubkey: ") + r, n, err := bytes.NewReader(srcPubKeyBytes), new(int64), new(error) + srcPubKey := account_.PubKeyDecoder(r, n, err).(account_.PubKey) + if *err != nil { + Exit(Fmt("Invalid PubKey. Error: %v", err)) + } + + // Get the state of the account. + var srcAccount *account_.Account + var srcAccountAddress = srcPubKey.Address() + var srcAccountBalanceStr = "unknown" + var srcAccountSequenceStr = "unknown" + srcAddress := srcPubKey.Address() + if state != nil { + srcAccount = state.GetAccount(srcAddress) + srcAccountBalanceStr = Fmt("%v", srcAccount.Balance) + srcAccountSequenceStr = Fmt("%v", srcAccount.Sequence+1) + } + + // Get the amount to send from src account + srcSendAmount := getUint64(Fmt("Enter amount to send from %X (total: %v): ", srcAccountAddress, srcAccountBalanceStr)) + + // Get the next sequence of src account + srcSendSequence := uint(getUint64(Fmt("Enter next sequence for %X (guess: %v): ", srcAccountAddress, srcAccountSequenceStr))) + + // Get dest address + dstAddress := getByteSliceFromHex("Enter destination address: ") + + // Get the amount to send to dst account + dstSendAmount := getUint64(Fmt("Enter amount to send to %X: ", dstAddress)) + + // Construct SendTx + tx := &block_.SendTx{ + Inputs: []*block_.TxInput{ + &block_.TxInput{ + Address: srcAddress, + Amount: srcSendAmount, + Sequence: srcSendSequence, + Signature: account_.SignatureEd25519{}, + PubKey: srcPubKey, + }, + }, + Outputs: []*block_.TxOutput{ + &block_.TxOutput{ + Address: dstAddress, + Amount: dstSendAmount, + }, + }, + } + + // Show the intermediate form. + fmt.Printf("Generated tx: %X\n", binary.BinaryBytes(tx)) + + // Get source privkey (for signing) + srcPrivKeyBytes := getByteSliceFromBase64("Enter source privkey (for signing): ") + r, n, err = bytes.NewReader(srcPrivKeyBytes), new(int64), new(error) + srcPrivKey := account_.PrivKeyDecoder(r, n, err).(account_.PrivKey) + if *err != nil { + Exit(Fmt("Invalid PrivKey. Error: %v", err)) + } + + // Sign + tx.Inputs[0].Signature = srcPrivKey.Sign(binary.BinaryBytes(tx)) + fmt.Printf("Signed tx: %X\n", binary.BinaryBytes(tx)) +} diff --git a/cmd/main.go b/cmd/main.go index 8cb9ed0e..b43e92e2 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -17,6 +17,7 @@ Commands: daemon Run the tendermint node daemon gen_account Generate new account keypair gen_validator Generate new validator keypair + gen_tx Generate new transaction probe_upnp Test UPnP functionality `) return @@ -30,6 +31,9 @@ Commands: gen_account() case "gen_validator": gen_validator() + case "gen_tx": + config.ParseFlags(args[1:]) + gen_tx() case "probe_upnp": probe_upnp() default: diff --git a/config/config.go b/config/config.go index ef19e5bb..51079bd7 100644 --- a/config/config.go +++ b/config/config.go @@ -125,6 +125,7 @@ func AddrBookFile() string { return rootDir + "/addrbook.json" } func PrivValidatorFile() string { return rootDir + "/priv_validator.json" } func DataDir() string { return rootDir + "/data" } +// The actual global config singleton object. var Config ConfigType func parseFlags(flags *flag.FlagSet, args []string) (printHelp bool) { diff --git a/db/db.go b/db/db.go index 011a8a60..3626ab00 100644 --- a/db/db.go +++ b/db/db.go @@ -41,6 +41,6 @@ func GetDB(name string) DB { dbs.Set(name, db) return db default: - panic("Unknown DB backend") + panic(Fmt("Unknown DB backend: %v", Config.DB.Backend)) } } diff --git a/state/genesis.go b/state/genesis.go index 5a2f524b..cadc1a69 100644 --- a/state/genesis.go +++ b/state/genesis.go @@ -2,7 +2,7 @@ package state import ( "bytes" - "encoding/base64" + "encoding/hex" "encoding/json" "io/ioutil" "time" @@ -61,7 +61,7 @@ func MakeGenesisState(db db_.DB, genDoc *GenesisDoc) *State { // Make accounts state tree accounts := merkle.NewIAVLTree(BasicCodec, AccountCodec, defaultAccountsCacheCapacity, db) for _, acc := range genDoc.Accounts { - address, err := base64.StdEncoding.DecodeString(acc.Address) + address, err := hex.DecodeString(acc.Address) if err != nil { Exit(Fmt("Invalid account address: %v", acc.Address)) } @@ -78,7 +78,7 @@ func MakeGenesisState(db db_.DB, genDoc *GenesisDoc) *State { validatorInfos := merkle.NewIAVLTree(BasicCodec, ValidatorInfoCodec, 0, db) validators := make([]*Validator, len(genDoc.Validators)) for i, val := range genDoc.Validators { - pubKeyBytes, err := base64.StdEncoding.DecodeString(val.PubKey) + pubKeyBytes, err := hex.DecodeString(val.PubKey) if err != nil { Exit(Fmt("Invalid validator pubkey: %v", val.PubKey)) } @@ -98,7 +98,7 @@ func MakeGenesisState(db db_.DB, genDoc *GenesisDoc) *State { FirstBondAmount: val.Amount, } for i, unbondTo := range val.UnbondTo { - address, err := base64.StdEncoding.DecodeString(unbondTo.Address) + address, err := hex.DecodeString(unbondTo.Address) if err != nil { Exit(Fmt("Invalid unbond-to address: %v", unbondTo.Address)) } diff --git a/state/priv_validator.go b/state/priv_validator.go index 06ffaa24..1de4e96f 100644 --- a/state/priv_validator.go +++ b/state/priv_validator.go @@ -4,7 +4,7 @@ package state import ( "bytes" - "encoding/base64" + "encoding/hex" "encoding/json" "errors" "fmt" @@ -93,15 +93,15 @@ func LoadPrivValidator(filename string) *PrivValidator { if err != nil { panic(err) } - address, err := base64.StdEncoding.DecodeString(privValJSON.Address) + address, err := hex.DecodeString(privValJSON.Address) if err != nil { panic(err) } - pubKeyBytes, err := base64.StdEncoding.DecodeString(privValJSON.PubKey) + pubKeyBytes, err := hex.DecodeString(privValJSON.PubKey) if err != nil { panic(err) } - privKeyBytes, err := base64.StdEncoding.DecodeString(privValJSON.PrivKey) + privKeyBytes, err := hex.DecodeString(privValJSON.PrivKey) if err != nil { panic(err) } @@ -137,9 +137,9 @@ func (privVal *PrivValidator) save() { func (privVal *PrivValidator) JSONBytes() []byte { privValJSON := PrivValidatorJSON{ - Address: base64.StdEncoding.EncodeToString(privVal.Address), - PubKey: base64.StdEncoding.EncodeToString(BinaryBytes(privVal.PubKey)), - PrivKey: base64.StdEncoding.EncodeToString(BinaryBytes(privVal.PrivKey)), + Address: hex.EncodeToString(privVal.Address), + PubKey: hex.EncodeToString(BinaryBytes(privVal.PubKey)), + PrivKey: hex.EncodeToString(BinaryBytes(privVal.PrivKey)), LastHeight: privVal.LastHeight, LastRound: privVal.LastRound, LastStep: privVal.LastStep,