-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feat/migrate-cosmos-to-new-api' into merge/migrate-cosm…
…os-to-new-api
- Loading branch information
Showing
16 changed files
with
1,079 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package cosmos | ||
|
||
import ( | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/renproject/multichain/api/address" | ||
) | ||
|
||
// An Address is a public address that can be encoded/decoded to/from strings. | ||
// Addresses are usually formatted different between different network | ||
// configurations. | ||
type Address sdk.AccAddress | ||
|
||
// AccAddress convert Address to sdk.AccAddress | ||
func (addr Address) AccAddress() sdk.AccAddress { | ||
return sdk.AccAddress(addr) | ||
} | ||
|
||
// String implements the Stringer interface | ||
func (addr Address) String() string { | ||
return sdk.AccAddress(addr).String() | ||
} | ||
|
||
// AddressEncodeDecoder encapsulates fields that implement the | ||
// address.EncodeDecoder interface | ||
type AddressEncodeDecoder struct { | ||
AddressEncoder | ||
AddressDecoder | ||
} | ||
|
||
// NewAddressEncodeDecoder creates a new address encoder-decoder | ||
func NewAddressEncodeDecoder(hrp string) AddressEncodeDecoder { | ||
return AddressEncodeDecoder{ | ||
AddressEncoder: AddressEncoder{}, | ||
AddressDecoder: NewAddressDecoder(hrp), | ||
} | ||
} | ||
|
||
// AddressEncoder implements the address.Encoder interface | ||
type AddressEncoder struct{} | ||
|
||
// AddressDecoder implements the address.Decoder interface | ||
type AddressDecoder struct { | ||
hrp string | ||
} | ||
|
||
// NewAddressDecoder creates a new address decoder | ||
func NewAddressDecoder(hrp string) AddressDecoder { | ||
return AddressDecoder{hrp: hrp} | ||
} | ||
|
||
// NewAddressEncoder creates a new address encoder | ||
func NewAddressEncoder() AddressEncoder { | ||
return AddressEncoder{} | ||
} | ||
|
||
// DecodeAddress consumes a human-readable representation of a cosmos | ||
// compatible address and decodes it to its raw bytes representation. | ||
func (decoder AddressDecoder) DecodeAddress(addr address.Address) (address.RawAddress, error) { | ||
sdk.GetConfig().SetBech32PrefixForAccount(decoder.hrp, decoder.hrp+"pub") | ||
rawAddr, err := sdk.AccAddressFromBech32(string(addr)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return address.RawAddress(rawAddr), nil | ||
} | ||
|
||
// EncodeAddress consumes raw bytes and encodes them to a human-readable | ||
// address format. | ||
func (encoder AddressEncoder) EncodeAddress(rawAddr address.RawAddress) (address.Address, error) { | ||
bech32Addr := sdk.AccAddress(rawAddr) | ||
return address.Address(bech32Addr.String()), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package cosmos_test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package cosmos | ||
|
||
import ( | ||
"context" | ||
"encoding/hex" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/renproject/multichain/api/account" | ||
"github.com/renproject/pack" | ||
|
||
cliContext "github.com/cosmos/cosmos-sdk/client/context" | ||
"github.com/cosmos/cosmos-sdk/codec" | ||
"github.com/cosmos/cosmos-sdk/x/auth" | ||
"github.com/cosmos/cosmos-sdk/x/auth/client/utils" | ||
rpchttp "github.com/tendermint/tendermint/rpc/client/http" | ||
) | ||
|
||
const ( | ||
// DefaultClientTimeout used by the Client. | ||
DefaultClientTimeout = time.Minute | ||
// DefaultClientTimeoutRetry used by the Client. | ||
DefaultClientTimeoutRetry = time.Second | ||
// DefaultClientHost used by the Client. This should only be used for local | ||
// deployments of the multichain. | ||
DefaultClientHost = "http://0.0.0.0:26657" | ||
// DefaultBroadcastMode configures the behaviour of a cosmos client while it | ||
// interacts with the cosmos node. Allowed broadcast modes can be async, sync | ||
// and block. "async" returns immediately after broadcasting, "sync" returns | ||
// after the transaction has been checked and "block" waits until the | ||
// transaction is committed to the chain. | ||
DefaultBroadcastMode = "sync" | ||
) | ||
|
||
// ClientOptions are used to parameterise the behaviour of the Client. | ||
type ClientOptions struct { | ||
Timeout time.Duration | ||
TimeoutRetry time.Duration | ||
Host pack.String | ||
BroadcastMode pack.String | ||
} | ||
|
||
// DefaultClientOptions returns ClientOptions with the default settings. These | ||
// settings are valid for use with the default local deployment of the | ||
// multichain. In production, the host, user, and password should be changed. | ||
func DefaultClientOptions() ClientOptions { | ||
return ClientOptions{ | ||
Timeout: DefaultClientTimeout, | ||
TimeoutRetry: DefaultClientTimeoutRetry, | ||
Host: pack.String(DefaultClientHost), | ||
BroadcastMode: pack.String(DefaultBroadcastMode), | ||
} | ||
} | ||
|
||
// WithHost sets the URL of the Bitcoin node. | ||
func (opts ClientOptions) WithHost(host pack.String) ClientOptions { | ||
opts.Host = host | ||
return opts | ||
} | ||
|
||
// Client interacts with an instance of the Cosmos based network using the REST | ||
// interface exposed by a lightclient node. | ||
type Client struct { | ||
opts ClientOptions | ||
cliCtx cliContext.CLIContext | ||
} | ||
|
||
// NewClient returns a new Client. | ||
func NewClient(opts ClientOptions, cdc *codec.Codec) account.Client { | ||
httpClient, err := rpchttp.NewWithTimeout(opts.Host.String(), "websocket", uint(opts.Timeout/time.Second)) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
cliCtx := cliContext.NewCLIContext().WithCodec(cdc).WithClient(httpClient).WithTrustNode(true) | ||
|
||
return &Client{ | ||
opts: opts, | ||
cliCtx: cliCtx, | ||
} | ||
} | ||
|
||
// Tx query transaction with txHash | ||
func (client *Client) Tx(ctx context.Context, txHash pack.Bytes) (account.Tx, pack.U64, error) { | ||
res, err := utils.QueryTx(client.cliCtx, hex.EncodeToString(txHash[:])) | ||
if err != nil { | ||
return &StdTx{}, pack.NewU64(0), fmt.Errorf("query fail: %v", err) | ||
} | ||
|
||
authStdTx := res.Tx.(auth.StdTx) | ||
if res.Code != 0 { | ||
return &StdTx{}, pack.NewU64(0), fmt.Errorf("tx failed code: %v, log: %v", res.Code, res.RawLog) | ||
} | ||
|
||
stdTx, err := parseStdTx(authStdTx) | ||
if err != nil { | ||
return &StdTx{}, pack.NewU64(0), fmt.Errorf("parse tx failed: %v", err) | ||
} | ||
|
||
return &stdTx, pack.NewU64(1), nil | ||
} | ||
|
||
// SubmitTx to the Cosmos based network. | ||
func (client *Client) SubmitTx(ctx context.Context, tx account.Tx) error { | ||
txBytes, err := tx.Serialize() | ||
if err != nil { | ||
return fmt.Errorf("bad \"submittx\": %v", err) | ||
} | ||
|
||
res, err := client.cliCtx.WithBroadcastMode(client.opts.BroadcastMode.String()).BroadcastTx(txBytes) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if res.Code != 0 { | ||
return fmt.Errorf("tx failed code: %v, log: %v", res.Code, res.RawLog) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package cosmos |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package cosmos_test | ||
|
||
import ( | ||
"testing" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
func TestCosmos(t *testing.T) { | ||
RegisterFailHandler(Fail) | ||
RunSpecs(t, "Cosmos Suite") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package cosmos_test | ||
|
||
// import ( | ||
// "encoding/hex" | ||
// "os" | ||
// "strings" | ||
// "time" | ||
|
||
// "github.com/tendermint/tendermint/crypto/secp256k1" | ||
|
||
// sdk "github.com/cosmos/cosmos-sdk/types" | ||
// "github.com/terra-project/core/app" | ||
|
||
// "github.com/renproject/multichain/chain/cosmos" | ||
// "github.com/renproject/multichain/compat/cosmoscompat" | ||
// "github.com/renproject/pack" | ||
|
||
// . "github.com/onsi/ginkgo" | ||
// . "github.com/onsi/gomega" | ||
// ) | ||
|
||
// var _ = Describe("Cosmos", func() { | ||
// Context("when submitting transactions", func() { | ||
// Context("when sending LUNA to multiple addresses", func() { | ||
// It("should work", func() { | ||
// // Load private key, and assume that the associated address has | ||
// // funds to spend. You can do this by setting TERRA_PK to the | ||
// // value specified in the `./multichaindeploy/.env` file. | ||
// pkEnv := os.Getenv("TERRA_PK") | ||
// if pkEnv == "" { | ||
// panic("TERRA_PK is undefined") | ||
// } | ||
|
||
// addrEnv := os.Getenv("TERRA_ADDRESS") | ||
// if addrEnv == "" { | ||
// panic("TERRA_ADDRESS is undefined") | ||
// } | ||
|
||
// // pkEnv := "a96e62ed3955e65be32703f12d87b6b5cf26039ecfa948dc5107a495418e5330" | ||
// // addrEnv := "terra10s4mg25tu6termrk8egltfyme4q7sg3hl8s38u" | ||
|
||
// pkBz, err := hex.DecodeString(pkEnv) | ||
// Expect(err).ToNot(HaveOccurred()) | ||
|
||
// var pk secp256k1.PrivKeySecp256k1 | ||
// copy(pk[:], pkBz) | ||
|
||
// addr := cosmoscompat.Address(pk.PubKey().Address()) | ||
|
||
// decoder := cosmos.NewAddressDecoder("terra") | ||
// expectedAddr, err := decoder.DecodeAddress(pack.NewString(addrEnv)) | ||
// Expect(err).ToNot(HaveOccurred()) | ||
// Expect(addr).Should(Equal(expectedAddr)) | ||
|
||
// pk1 := secp256k1.GenPrivKey() | ||
// pk2 := secp256k1.GenPrivKey() | ||
|
||
// recipient1 := sdk.AccAddress(pk1.PubKey().Address()) | ||
// recipient2 := sdk.AccAddress(pk2.PubKey().Address()) | ||
|
||
// msgs := []cosmoscompat.MsgSend{ | ||
// { | ||
// FromAddress: cosmoscompat.Address(addr), | ||
// ToAddress: cosmoscompat.Address(recipient1), | ||
// Amount: cosmoscompat.Coins{ | ||
// { | ||
// Denom: "uluna", | ||
// Amount: pack.U64(1000000), | ||
// }, | ||
// }, | ||
// }, | ||
// { | ||
// FromAddress: cosmoscompat.Address(addr), | ||
// ToAddress: cosmoscompat.Address(recipient2), | ||
// Amount: cosmoscompat.Coins{ | ||
// { | ||
// Denom: "uluna", | ||
// Amount: pack.U64(2000000), | ||
// }, | ||
// }, | ||
// }, | ||
// } | ||
|
||
// client := cosmoscompat.NewClient(cosmoscompat.DefaultClientOptions(), app.MakeCodec()) | ||
// account, err := client.Account(addr) | ||
// Expect(err).NotTo(HaveOccurred()) | ||
|
||
// txBuilder := cosmos.NewTxBuilder(cosmoscompat.TxOptions{ | ||
// AccountNumber: account.AccountNumber, | ||
// SequenceNumber: account.SequenceNumber, | ||
// Gas: 200000, | ||
// ChainID: "testnet", | ||
// Memo: "multichain", | ||
// Fees: cosmoscompat.Coins{ | ||
// { | ||
// Denom: "uluna", | ||
// Amount: pack.U64(3000), | ||
// }, | ||
// }, | ||
// }).WithCodec(app.MakeCodec()) | ||
|
||
// tx, err := txBuilder.BuildTx(msgs) | ||
// Expect(err).NotTo(HaveOccurred()) | ||
|
||
// sigBytes, err := pk.Sign(tx.SigBytes()) | ||
// Expect(err).NotTo(HaveOccurred()) | ||
|
||
// pubKey := pk.PubKey().(secp256k1.PubKeySecp256k1) | ||
// err = tx.Sign([]cosmoscompat.StdSignature{ | ||
// { | ||
// Signature: pack.NewBytes(sigBytes), | ||
// PubKey: pack.NewBytes(pubKey[:]), | ||
// }, | ||
// }) | ||
// Expect(err).NotTo(HaveOccurred()) | ||
|
||
// txHash, err := client.SubmitTx(tx, pack.NewString("sync")) | ||
// Expect(err).NotTo(HaveOccurred()) | ||
|
||
// for { | ||
// // Loop until the transaction has at least a few | ||
// // confirmations. This implies that the transaction is | ||
// // definitely valid, and the test has passed. We were | ||
// // successfully able to use the multichain to construct and | ||
// // submit a Bitcoin transaction! | ||
// _, err := client.Tx(txHash) | ||
// if err == nil { | ||
// break | ||
// } | ||
|
||
// if !strings.Contains(err.Error(), "not found") { | ||
// Expect(err).NotTo(HaveOccurred()) | ||
// } | ||
|
||
// time.Sleep(10 * time.Second) | ||
// } | ||
// }) | ||
// }) | ||
// }) | ||
// }) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package cosmos | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/renproject/multichain/api/gas" | ||
"github.com/renproject/pack" | ||
) | ||
|
||
// A GasEstimator returns the gas-per-byte that is needed in order to confirm | ||
// transactions with an estimated maximum delay of one block. In distributed | ||
// networks that collectively build, sign, and submit transactions, it is | ||
// important that all nodes in the network have reached consensus on the | ||
// gas-per-byte. | ||
type GasEstimator struct { | ||
gasPerByte pack.U256 | ||
} | ||
|
||
// NewGasEstimator returns a simple gas estimator that always returns the same | ||
// amount of gas-per-byte. | ||
func NewGasEstimator(gasPerByte pack.U256) gas.Estimator { | ||
return &GasEstimator{ | ||
gasPerByte: gasPerByte, | ||
} | ||
} | ||
|
||
// EstimateGasPrice returns gas required per byte for Cosmos-compatible chains. | ||
func (gasEstimator *GasEstimator) EstimateGasPrice(ctx context.Context) (pack.U256, error) { | ||
return gasEstimator.gasPerByte, nil | ||
} |
Oops, something went wrong.