Skip to content

Commit

Permalink
Merge pull request #520 from CosmWasm/ibc-callbacks
Browse files Browse the repository at this point in the history
IBC Callbacks
  • Loading branch information
chipshort authored Jun 26, 2024
2 parents 1de5cd8 + ea935a7 commit 15d29dc
Show file tree
Hide file tree
Showing 7 changed files with 313 additions and 10 deletions.
24 changes: 24 additions & 0 deletions internal/api/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,30 @@ struct UnmanagedVector ibc_packet_timeout(struct cache_t *cache,
struct GasReport *gas_report,
struct UnmanagedVector *error_msg);

struct UnmanagedVector ibc_source_callback(struct cache_t *cache,
struct ByteSliceView checksum,
struct ByteSliceView env,
struct ByteSliceView msg,
struct Db db,
struct GoApi api,
struct GoQuerier querier,
uint64_t gas_limit,
bool print_debug,
struct GasReport *gas_report,
struct UnmanagedVector *error_msg);

struct UnmanagedVector ibc_destination_callback(struct cache_t *cache,
struct ByteSliceView checksum,
struct ByteSliceView env,
struct ByteSliceView msg,
struct Db db,
struct GoApi api,
struct GoQuerier querier,
uint64_t gas_limit,
bool print_debug,
struct GasReport *gas_report,
struct UnmanagedVector *error_msg);

struct UnmanagedVector new_unmanaged_vector(bool nil, const uint8_t *ptr, uintptr_t length);

void destroy_unmanaged_vector(struct UnmanagedVector v);
Expand Down
84 changes: 84 additions & 0 deletions internal/api/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,90 @@ func IBCPacketTimeout(
return copyAndDestroyUnmanagedVector(res), convertGasReport(gasReport), nil
}

func IBCSourceCallback(
cache Cache,
checksum []byte,
env []byte,
msg []byte,
gasMeter *types.GasMeter,
store types.KVStore,
api *types.GoAPI,
querier *Querier,
gasLimit uint64,
printDebug bool,
) ([]byte, types.GasReport, error) {
cs := makeView(checksum)
defer runtime.KeepAlive(checksum)
e := makeView(env)
defer runtime.KeepAlive(env)
msgBytes := makeView(msg)
defer runtime.KeepAlive(msg)
var pinner runtime.Pinner
pinner.Pin(gasMeter)
checkAndPinAPI(api, pinner)
checkAndPinQuerier(querier, pinner)
defer pinner.Unpin()

callID := startCall()
defer endCall(callID)

dbState := buildDBState(store, callID)
db := buildDB(&dbState, gasMeter)
a := buildAPI(api)
q := buildQuerier(querier)
var gasReport C.GasReport
errmsg := uninitializedUnmanagedVector()

res, err := C.ibc_source_callback(cache.ptr, cs, e, msgBytes, db, a, q, cu64(gasLimit), cbool(printDebug), &gasReport, &errmsg)
if err != nil && err.(syscall.Errno) != C.ErrnoValue_Success {
// Depending on the nature of the error, `gasUsed` will either have a meaningful value, or just 0.
return nil, convertGasReport(gasReport), errorWithMessage(err, errmsg)
}
return copyAndDestroyUnmanagedVector(res), convertGasReport(gasReport), nil
}

func IBCDestinationCallback(
cache Cache,
checksum []byte,
env []byte,
msg []byte,
gasMeter *types.GasMeter,
store types.KVStore,
api *types.GoAPI,
querier *Querier,
gasLimit uint64,
printDebug bool,
) ([]byte, types.GasReport, error) {
cs := makeView(checksum)
defer runtime.KeepAlive(checksum)
e := makeView(env)
defer runtime.KeepAlive(env)
msgBytes := makeView(msg)
defer runtime.KeepAlive(msg)
var pinner runtime.Pinner
pinner.Pin(gasMeter)
checkAndPinAPI(api, pinner)
checkAndPinQuerier(querier, pinner)
defer pinner.Unpin()

callID := startCall()
defer endCall(callID)

dbState := buildDBState(store, callID)
db := buildDB(&dbState, gasMeter)
a := buildAPI(api)
q := buildQuerier(querier)
var gasReport C.GasReport
errmsg := uninitializedUnmanagedVector()

res, err := C.ibc_destination_callback(cache.ptr, cs, e, msgBytes, db, a, q, cu64(gasLimit), cbool(printDebug), &gasReport, &errmsg)
if err != nil && err.(syscall.Errno) != C.ErrnoValue_Success {
// Depending on the nature of the error, `gasUsed` will either have a meaningful value, or just 0.
return nil, convertGasReport(gasReport), errorWithMessage(err, errmsg)
}
return copyAndDestroyUnmanagedVector(res), convertGasReport(gasReport), nil
}

func convertGasReport(report C.GasReport) types.GasReport {
return types.GasReport{
Limit: uint64(report.limit),
Expand Down
69 changes: 69 additions & 0 deletions lib_libwasmvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,75 @@ func (vm *VM) IBCPacketTimeout(
return &result, gasReport.UsedInternally, nil
}

// IBCSourceCallback is available on IBC-enabled contracts with the corresponding entrypoint
// and should be called when the response (ack or timeout) for an outgoing callbacks-enabled packet
// (previously sent by this contract) is received.
func (vm *VM) IBCSourceCallback(
checksum Checksum,
env types.Env,
msg types.IBCSourceCallbackMsg,
store KVStore,
goapi GoAPI,
querier Querier,
gasMeter GasMeter,
gasLimit uint64,
deserCost types.UFraction,
) (*types.IBCBasicResult, uint64, error) {
envBin, err := json.Marshal(env)
if err != nil {
return nil, 0, err
}
msgBin, err := json.Marshal(msg)
if err != nil {
return nil, 0, err
}
data, gasReport, err := api.IBCSourceCallback(vm.cache, checksum, envBin, msgBin, &gasMeter, store, &goapi, &querier, gasLimit, vm.printDebug)
if err != nil {
return nil, gasReport.UsedInternally, err
}

var result types.IBCBasicResult
err = DeserializeResponse(gasLimit, deserCost, &gasReport, data, &result)
if err != nil {
return nil, gasReport.UsedInternally, err
}
return &result, gasReport.UsedInternally, nil
}

// IBCDestinationCallback is available on IBC-enabled contracts with the corresponding entrypoint
// and should be called when an incoming callbacks-enabled IBC packet is received.
func (vm *VM) IBCDestinationCallback(
checksum Checksum,
env types.Env,
msg types.IBCDestinationCallbackMsg,
store KVStore,
goapi GoAPI,
querier Querier,
gasMeter GasMeter,
gasLimit uint64,
deserCost types.UFraction,
) (*types.IBCBasicResult, uint64, error) {
envBin, err := json.Marshal(env)
if err != nil {
return nil, 0, err
}
msgBin, err := json.Marshal(msg)
if err != nil {
return nil, 0, err
}
data, gasReport, err := api.IBCDestinationCallback(vm.cache, checksum, envBin, msgBin, &gasMeter, store, &goapi, &querier, gasLimit, vm.printDebug)
if err != nil {
return nil, gasReport.UsedInternally, err
}

var result types.IBCBasicResult
err = DeserializeResponse(gasLimit, deserCost, &gasReport, data, &result)
if err != nil {
return nil, gasReport.UsedInternally, err
}
return &result, gasReport.UsedInternally, nil
}

func compileCost(code WasmCode) uint64 {
// CostPerByte is how much CosmWasm gas is charged *per byte* for compiling WASM code.
// Benchmarks and numbers (in SDK Gas) were discussed in:
Expand Down
14 changes: 7 additions & 7 deletions libwasmvm/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions libwasmvm/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,30 @@ struct UnmanagedVector ibc_packet_timeout(struct cache_t *cache,
struct GasReport *gas_report,
struct UnmanagedVector *error_msg);

struct UnmanagedVector ibc_source_callback(struct cache_t *cache,
struct ByteSliceView checksum,
struct ByteSliceView env,
struct ByteSliceView msg,
struct Db db,
struct GoApi api,
struct GoQuerier querier,
uint64_t gas_limit,
bool print_debug,
struct GasReport *gas_report,
struct UnmanagedVector *error_msg);

struct UnmanagedVector ibc_destination_callback(struct cache_t *cache,
struct ByteSliceView checksum,
struct ByteSliceView env,
struct ByteSliceView msg,
struct Db db,
struct GoApi api,
struct GoQuerier querier,
uint64_t gas_limit,
bool print_debug,
struct GasReport *gas_report,
struct UnmanagedVector *error_msg);

struct UnmanagedVector new_unmanaged_vector(bool nil, const uint8_t *ptr, uintptr_t length);

void destroy_unmanaged_vector(struct UnmanagedVector v);
Expand Down
67 changes: 64 additions & 3 deletions libwasmvm/src/calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ use time::{format_description::well_known::Rfc3339, OffsetDateTime};
use cosmwasm_std::Checksum;
use cosmwasm_vm::{
call_execute_raw, call_ibc_channel_close_raw, call_ibc_channel_connect_raw,
call_ibc_channel_open_raw, call_ibc_packet_ack_raw, call_ibc_packet_receive_raw,
call_ibc_packet_timeout_raw, call_instantiate_raw, call_migrate_raw, call_query_raw,
call_reply_raw, call_sudo_raw, Backend, Cache, Instance, InstanceOptions, VmResult,
call_ibc_channel_open_raw, call_ibc_destination_callback_raw, call_ibc_packet_ack_raw,
call_ibc_packet_receive_raw, call_ibc_packet_timeout_raw, call_ibc_source_callback_raw,
call_instantiate_raw, call_migrate_raw, call_query_raw, call_reply_raw, call_sudo_raw, Backend,
Cache, Instance, InstanceOptions, VmResult,
};

use crate::api::GoApi;
Expand Down Expand Up @@ -395,6 +396,66 @@ pub extern "C" fn ibc_packet_timeout(
)
}

#[no_mangle]
pub extern "C" fn ibc_source_callback(
cache: *mut cache_t,
checksum: ByteSliceView,
env: ByteSliceView,
msg: ByteSliceView,
db: Db,
api: GoApi,
querier: GoQuerier,
gas_limit: u64,
print_debug: bool,
gas_report: Option<&mut GasReport>,
error_msg: Option<&mut UnmanagedVector>,
) -> UnmanagedVector {
call_2_args(
call_ibc_source_callback_raw,
cache,
checksum,
env,
msg,
db,
api,
querier,
gas_limit,
print_debug,
gas_report,
error_msg,
)
}

#[no_mangle]
pub extern "C" fn ibc_destination_callback(
cache: *mut cache_t,
checksum: ByteSliceView,
env: ByteSliceView,
msg: ByteSliceView,
db: Db,
api: GoApi,
querier: GoQuerier,
gas_limit: u64,
print_debug: bool,
gas_report: Option<&mut GasReport>,
error_msg: Option<&mut UnmanagedVector>,
) -> UnmanagedVector {
call_2_args(
call_ibc_destination_callback_raw,
cache,
checksum,
env,
msg,
db,
api,
querier,
gas_limit,
print_debug,
gas_report,
error_msg,
)
}

type VmFn2Args = fn(
instance: &mut Instance<GoApi, GoStorage, GoQuerier>,
arg1: &[u8],
Expand Down
Loading

0 comments on commit 15d29dc

Please sign in to comment.