Skip to content

Commit

Permalink
Merge pull request #1943 from CosmWasm/go-gen-fixes
Browse files Browse the repository at this point in the history
go-gen fixes
  • Loading branch information
chipshort authored Nov 22, 2023
2 parents ddcd300 + f9d365c commit 8fe095f
Show file tree
Hide file tree
Showing 7 changed files with 347 additions and 18 deletions.
112 changes: 96 additions & 16 deletions packages/go-gen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,22 @@ fn main() -> Result<()> {

/// Generates the Go code for the given schema
fn generate_go(root: RootSchema) -> Result<String> {
let title = replace_acronyms(
root.schema
.metadata
.as_ref()
.and_then(|m| m.title.as_ref())
.context("failed to get type name")?,
);
let title = root
.schema
.metadata
.as_ref()
.and_then(|m| m.title.as_ref())
.context("failed to get type name")?;

let mut types = vec![];
build_type(&title, &root.schema, &mut types)
build_type(title, &root.schema, &mut types)
.with_context(|| format!("failed to generate {title}"))?;

// go through additional definitions
for (name, additional_type) in &root.definitions {
additional_type
.object()
.map(|def| build_type(&replace_acronyms(name), def, &mut types))
.map(|def| build_type(name, def, &mut types))
.and_then(|r| r)
.context("failed to generate additional definitions")?;
}
Expand Down Expand Up @@ -107,7 +106,7 @@ pub fn build_struct(
let fields = fields.collect::<Result<Vec<_>>>()?;

Ok(GoStruct {
name: to_pascal_case(name),
name: replace_acronyms(to_pascal_case(name)),
docs,
fields,
})
Expand All @@ -121,6 +120,7 @@ pub fn build_enum<'a>(
variants: impl Iterator<Item = &'a Schema>,
additional_structs: &mut Vec<GoStruct>,
) -> Result<GoStruct> {
let name = replace_acronyms(name);
let docs = documentation(enm);

// go through all fields
Expand All @@ -131,18 +131,14 @@ pub fn build_enum<'a>(
.with_context(|| format!("expected schema object for enum variants of {name}"))?;

// analyze the variant
let variant_field = build_enum_variant(v, name, additional_structs)
let variant_field = build_enum_variant(v, &name, additional_structs)
.context("failed to extract enum variant")?;

anyhow::Ok(variant_field)
});
let fields = fields.collect::<Result<Vec<_>>>()?;

Ok(GoStruct {
name: name.to_string(),
docs,
fields,
})
Ok(GoStruct { name, docs, fields })
}

/// Tries to extract the name and type of the given enum variant and returns it as a `GoField`.
Expand Down Expand Up @@ -433,6 +429,16 @@ mod tests {
compare_codes!(cosmwasm_std::WasmQuery);
}

#[test]
fn messages_work() {
compare_codes!(cosmwasm_std::BankMsg);
compare_codes!(cosmwasm_std::StakingMsg);
compare_codes!(cosmwasm_std::DistributionMsg);
compare_codes!(cosmwasm_std::IbcMsg);
compare_codes!(cosmwasm_std::WasmMsg);
// compare_codes!(cosmwasm_std::GovMsg); // TODO: currently fails because of VoteOption
}

#[test]
fn array_item_type_works() {
#[cw_serde]
Expand Down Expand Up @@ -468,4 +474,78 @@ mod tests {
}"#,
);
}

#[test]
fn accronym_replacement_works() {
#[cw_serde]
struct IbcStruct {
a: IbcSubStruct,
b: IbcSubEnum,
}
#[cw_serde]
enum IbcEnum {
A(IbcSubStruct),
B(IbcSubEnum),
}
#[cw_serde]
struct IbcSubStruct {}
#[cw_serde]
enum IbcSubEnum {
A(String),
}

let code = generate_go(cosmwasm_schema::schema_for!(IbcStruct)).unwrap();
assert_code_eq(
code,
r#"
type IBCStruct struct {
A IBCSubStruct `json:"a"`
B IBCSubEnum `json:"b"`
}
type IBCSubEnum struct {
A string `json:"a,omitempty"`
}
type IBCSubStruct struct {
}
"#,
);

let code = generate_go(cosmwasm_schema::schema_for!(IbcEnum)).unwrap();
assert_code_eq(
code,
r#"
type IBCEnum struct {
A *IBCSubStruct `json:"a,omitempty"`
B *IBCSubEnum `json:"b,omitempty"`
}
type IBCSubEnum struct {
A string `json:"a,omitempty"`
}
type IBCSubStruct struct {
}
"#,
);
}

#[test]
fn timestamp_works() {
use cosmwasm_std::Timestamp;

#[cw_serde]
struct A {
a: Timestamp,
b: Option<Timestamp>,
}

let code = generate_go(cosmwasm_schema::schema_for!(A)).unwrap();
assert_code_eq(
code,
r#"
type A struct {
A Uint64 `json:"a"`
B *Uint64 `json:"b,omitempty"`
}
"#,
);
}
}
10 changes: 8 additions & 2 deletions packages/go-gen/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ pub fn schema_object_type(
replace_custom_type(title)
} else if let Some(reference) = &schema.reference {
// if it has a reference, strip the path and use that
replace_custom_type(
replace_custom_type(&replace_acronyms(
reference
.split('/')
.last()
.expect("split should always return at least one item"),
)
))
} else if let Some(t) = &schema.instance_type {
type_from_instance_type(schema, type_context, t, additional_structs)?
} else if let Some(subschemas) = schema.subschemas.as_ref().and_then(|s| s.any_of.as_ref()) {
Expand Down Expand Up @@ -259,13 +259,19 @@ pub fn documentation(schema: &SchemaObject) -> Option<String> {
/// If the given type is not a special type, returns `None`.
pub fn custom_type_of(ty: &str) -> Option<&str> {
match ty {
"Uint64" => Some("Uint64"),
"Uint128" => Some("string"),
"Int64" => Some("Int64"),
"Int128" => Some("string"),
"Binary" => Some("[]byte"),
"HexBinary" => Some("string"),
"Checksum" => Some("Checksum"),
"Addr" => Some("string"),
"Decimal" => Some("string"),
"Decimal256" => Some("string"),
"SignedDecimal" => Some("string"),
"SignedDecimal256" => Some("string"),
"Timestamp" => Some("Uint64"),
_ => None,
}
}
Expand Down
24 changes: 24 additions & 0 deletions packages/go-gen/tests/cosmwasm_std__BankMsg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SendMsg contains instructions for a Cosmos-SDK/SendMsg
// It has a fixed interface here and should be converted into the proper SDK format before dispatching
type SendMsg struct {
Amount []Coin `json:"amount"`
ToAddress string `json:"to_address"`
}

// BurnMsg will burn the given coins from the contract's account.
// There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper.
// Important if a contract controls significant token supply that must be retired.
type BurnMsg struct {
Amount []Coin `json:"amount"`
}

type BankMsg struct {
Send *SendMsg `json:"send,omitempty"`
Burn *BurnMsg `json:"burn,omitempty"`
}

// Coin is a string representation of the sdk.Coin type (more portable than sdk.Int)
type Coin struct {
Amount string `json:"amount"` // string encoing of decimal value, eg. "12.3456"
Denom string `json:"denom"` // type, eg. "ATOM"
}
32 changes: 32 additions & 0 deletions packages/go-gen/tests/cosmwasm_std__DistributionMsg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SetWithdrawAddressMsg is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37).
// `delegator_address` is automatically filled with the current contract's address.
type SetWithdrawAddressMsg struct {
// Address contains the `delegator_address` of a MsgSetWithdrawAddress
Address string `json:"address"`
}

// WithdrawDelegatorRewardMsg is translated to a [MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50).
// `delegator_address` is automatically filled with the current contract's address.
type WithdrawDelegatorRewardMsg struct {
// Validator contains `validator_address` of a MsgWithdrawDelegatorReward
Validator string `json:"validator"`
}

// FundCommunityPoolMsg is translated to a [MsgFundCommunityPool](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#LL69C1-L76C2).
// `depositor` is automatically filled with the current contract's address
type FundCommunityPoolMsg struct {
// Amount is the list of coins to be send to the community pool
Amount []Coin `json:"amount"`
}

type DistributionMsg struct {
SetWithdrawAddress *SetWithdrawAddressMsg `json:"set_withdraw_address,omitempty"`
WithdrawDelegatorReward *WithdrawDelegatorRewardMsg `json:"withdraw_delegator_reward,omitempty"`
FundCommunityPool *FundCommunityPoolMsg `json:"fund_community_pool,omitempty"`
}

// Coin is a string representation of the sdk.Coin type (more portable than sdk.Int)
type Coin struct {
Amount string `json:"amount"` // string encoing of decimal value, eg. "12.3456"
Denom string `json:"denom"` // type, eg. "ATOM"
}
47 changes: 47 additions & 0 deletions packages/go-gen/tests/cosmwasm_std__IbcMsg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
type TransferMsg struct {
Amount Coin `json:"amount"`
ChannelID string `json:"channel_id"`
Memo string `json:"memo,omitempty"` // this is not yet in wasmvm, but will be soon
Timeout IBCTimeout `json:"timeout"`
ToAddress string `json:"to_address"`
}
type SendPacketMsg struct {
ChannelID string `json:"channel_id"`
Data []byte `json:"data"`
Timeout IBCTimeout `json:"timeout"`
}
type CloseChannelMsg struct {
ChannelID string `json:"channel_id"`
}

type IBCMsg struct {
Transfer *TransferMsg `json:"transfer,omitempty"`
SendPacket *SendPacketMsg `json:"send_packet,omitempty"`
CloseChannel *CloseChannelMsg `json:"close_channel,omitempty"`
}

// Coin is a string representation of the sdk.Coin type (more portable than sdk.Int)
type Coin struct {
Amount string `json:"amount"` // string encoing of decimal value, eg. "12.3456"
Denom string `json:"denom"` // type, eg. "ATOM"
}

// IBCTimeout is the timeout for an IBC packet. At least one of block and timestamp is required.
type IBCTimeout struct {
Block *IBCTimeoutBlock `json:"block,omitempty"` // in wasmvm, this does not have "omitempty"
// Nanoseconds since UNIX epoch
Timestamp *Uint64 `json:"timestamp,omitempty"`
}

// IBCTimeoutBlock Height is a monotonically increasing data type
// that can be compared against another Height for the purposes of updating and
// freezing clients.
// Ordering is (revision_number, timeout_height)
type IBCTimeoutBlock struct {
// block height after which the packet times out.
// the height within the given revision
Height uint64 `json:"height"`
// the version that the client is currently on
// (eg. after reseting the chain this could increment 1 as height drops to 0)
Revision uint64 `json:"revision"`
}
25 changes: 25 additions & 0 deletions packages/go-gen/tests/cosmwasm_std__StakingMsg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
type DelegateMsg struct {
Amount Coin `json:"amount"`
Validator string `json:"validator"`
}
type UndelegateMsg struct {
Amount Coin `json:"amount"`
Validator string `json:"validator"`
}
type RedelegateMsg struct {
Amount Coin `json:"amount"`
DstValidator string `json:"dst_validator"`
SrcValidator string `json:"src_validator"`
}

type StakingMsg struct {
Delegate *DelegateMsg `json:"delegate,omitempty"`
Undelegate *UndelegateMsg `json:"undelegate,omitempty"`
Redelegate *RedelegateMsg `json:"redelegate,omitempty"`
}

// Coin is a string representation of the sdk.Coin type (more portable than sdk.Int)
type Coin struct {
Amount string `json:"amount"` // string encoing of decimal value, eg. "12.3456"
Denom string `json:"denom"` // type, eg. "ATOM"
}
Loading

0 comments on commit 8fe095f

Please sign in to comment.