diff --git a/cosmwasm/packages/enclave-ffi-types/src/types.rs b/cosmwasm/packages/enclave-ffi-types/src/types.rs
index a9b675522..109dbfe69 100644
--- a/cosmwasm/packages/enclave-ffi-types/src/types.rs
+++ b/cosmwasm/packages/enclave-ffi-types/src/types.rs
@@ -154,6 +154,8 @@ pub enum EnclaveError {
Panic,
#[display(fmt = "enclave ran out of heap memory")]
OutOfMemory,
+ #[display(fmt = "depth of nested contract calls exceeded")]
+ ExceededRecursionLimit,
/// Unexpected Error happened, no more details available
#[display(fmt = "unknown error")]
Unknown,
diff --git a/cosmwasm/packages/std/src/errors/system_error.rs b/cosmwasm/packages/std/src/errors/system_error.rs
index 6e317bb58..77a700181 100644
--- a/cosmwasm/packages/std/src/errors/system_error.rs
+++ b/cosmwasm/packages/std/src/errors/system_error.rs
@@ -21,6 +21,7 @@ pub enum SystemError {
NoSuchContract { addr: HumanAddr },
Unknown {},
UnsupportedRequest { kind: String },
+ ExceededRecursionLimit {},
}
impl std::error::Error for SystemError {}
@@ -45,6 +46,7 @@ impl std::fmt::Display for SystemError {
SystemError::UnsupportedRequest { kind } => {
write!(f, "Unsupported query type: {}", kind)
}
+ SystemError::ExceededRecursionLimit {} => write!(f, "Query recursion limit exceeded"),
}
}
}
diff --git a/cosmwasm/packages/wasmi-runtime/Enclave.config.prod.xml b/cosmwasm/packages/wasmi-runtime/Enclave.config.prod.xml
index f2b1d4248..feb1e1dbd 100644
--- a/cosmwasm/packages/wasmi-runtime/Enclave.config.prod.xml
+++ b/cosmwasm/packages/wasmi-runtime/Enclave.config.prod.xml
@@ -3,7 +3,7 @@
0
0
0x800000
- 0x8000000
+ 0x10000000
1
1
1
diff --git a/cosmwasm/packages/wasmi-runtime/Enclave.config.xml b/cosmwasm/packages/wasmi-runtime/Enclave.config.xml
index 8df1c3bb5..04e8b068b 100644
--- a/cosmwasm/packages/wasmi-runtime/Enclave.config.xml
+++ b/cosmwasm/packages/wasmi-runtime/Enclave.config.xml
@@ -3,7 +3,7 @@
0
0
0x800000
- 0x4000000
+ 0x10000000
1
1
0
diff --git a/cosmwasm/packages/wasmi-runtime/src/cosmwasm/system_error.rs b/cosmwasm/packages/wasmi-runtime/src/cosmwasm/system_error.rs
index 9637c236a..5ac65817d 100644
--- a/cosmwasm/packages/wasmi-runtime/src/cosmwasm/system_error.rs
+++ b/cosmwasm/packages/wasmi-runtime/src/cosmwasm/system_error.rs
@@ -23,6 +23,7 @@ pub enum SystemError {
NoSuchContract { addr: HumanAddr },
Unknown {},
UnsupportedRequest { kind: String },
+ ExceededRecursionLimit {},
}
pub type SystemResult = Result;
diff --git a/cosmwasm/packages/wasmi-runtime/src/exports.rs b/cosmwasm/packages/wasmi-runtime/src/exports.rs
index 9da5daf03..b59e74b3c 100644
--- a/cosmwasm/packages/wasmi-runtime/src/exports.rs
+++ b/cosmwasm/packages/wasmi-runtime/src/exports.rs
@@ -13,7 +13,7 @@ use crate::results::{
result_query_success_to_queryresult,
};
use crate::{
- oom_handler,
+ oom_handler, recursion_depth,
utils::{validate_const_ptr, validate_mut_ptr},
};
@@ -116,6 +116,19 @@ pub unsafe extern "C" fn ecall_init(
sig_info: *const u8,
sig_info_len: usize,
) -> InitResult {
+ let _recursion_guard = match recursion_depth::guard() {
+ Ok(rg) => rg,
+ Err(err) => {
+ // https://github.com/enigmampc/SecretNetwork/pull/517#discussion_r481924571
+ // I believe that this error condition is currently unreachable.
+ // I think we can safely remove it completely right now, and have
+ // recursion_depth::increment() simply increment the counter with no further checks,
+ // but i wanted to stay on the safe side here, in case something changes in the
+ // future, and we can easily spot that we forgot to add a limit somewhere.
+ error!("recursion limit exceeded, can not perform init!");
+ return InitResult::Failure { err };
+ }
+ };
if let Err(err) = oom_handler::register_oom_handler() {
error!("Could not register OOM handler!");
return InitResult::Failure { err };
@@ -200,6 +213,19 @@ pub unsafe extern "C" fn ecall_handle(
sig_info: *const u8,
sig_info_len: usize,
) -> HandleResult {
+ let _recursion_guard = match recursion_depth::guard() {
+ Ok(rg) => rg,
+ Err(err) => {
+ // https://github.com/enigmampc/SecretNetwork/pull/517#discussion_r481924571
+ // I believe that this error condition is currently unreachable.
+ // I think we can safely remove it completely right now, and have
+ // recursion_depth::increment() simply increment the counter with no further checks,
+ // but i wanted to stay on the safe side here, in case something changes in the
+ // future, and we can easily spot that we forgot to add a limit somewhere.
+ error!("recursion limit exceeded, can not perform handle!");
+ return HandleResult::Failure { err };
+ }
+ };
if let Err(err) = oom_handler::register_oom_handler() {
error!("Could not register OOM handler!");
return HandleResult::Failure { err };
@@ -280,6 +306,19 @@ pub unsafe extern "C" fn ecall_query(
msg: *const u8,
msg_len: usize,
) -> QueryResult {
+ let _recursion_guard = match recursion_depth::guard() {
+ Ok(rg) => rg,
+ Err(err) => {
+ // https://github.com/enigmampc/SecretNetwork/pull/517#discussion_r481924571
+ // I believe that this error condition is currently unreachable.
+ // I think we can safely remove it completely right now, and have
+ // recursion_depth::increment() simply increment the counter with no further checks,
+ // but i wanted to stay on the safe side here, in case something changes in the
+ // future, and we can easily spot that we forgot to add a limit somewhere.
+ error!("recursion limit exceeded, can not perform query!");
+ return QueryResult::Failure { err };
+ }
+ };
if let Err(err) = oom_handler::register_oom_handler() {
error!("Could not register OOM handler!");
return QueryResult::Failure { err };
diff --git a/cosmwasm/packages/wasmi-runtime/src/lib.rs b/cosmwasm/packages/wasmi-runtime/src/lib.rs
index e726753ce..4e9a3dbff 100644
--- a/cosmwasm/packages/wasmi-runtime/src/lib.rs
+++ b/cosmwasm/packages/wasmi-runtime/src/lib.rs
@@ -21,6 +21,7 @@ pub mod exports;
pub mod imports;
pub mod logger;
mod oom_handler;
+mod recursion_depth;
pub mod registration;
use std::env;
diff --git a/cosmwasm/packages/wasmi-runtime/src/oom_handler.rs b/cosmwasm/packages/wasmi-runtime/src/oom_handler.rs
index 4caa9d091..40dd9c6de 100644
--- a/cosmwasm/packages/wasmi-runtime/src/oom_handler.rs
+++ b/cosmwasm/packages/wasmi-runtime/src/oom_handler.rs
@@ -72,12 +72,13 @@ impl SafetyBuffer {
}
lazy_static! {
- /// SAFETY_BUFFER is a 32 MiB of SafetyBuffer. This is occupying 50% of available memory
- /// to be extra sure this is enough.
+ /// SAFETY_BUFFER is a 4 MiB of SafetyBuffer. This is twice the bare minimum to unwind after
+ /// a best-case OOM event. thanks to the recursion limit on queries, together with other memory
+ /// limits, we don't expect to hit OOM, and this mechanism remains in place just in case.
/// 2 MiB is the minimum allowed buffer. If we don't succeed to allocate 2 MiB, we throw a panic,
- /// if we do succeed to allocate 2 MiB but less than 32 MiB than we move on and will try to allocate
+ /// if we do succeed to allocate 2 MiB but less than 4 MiB than we move on and will try to allocate
/// the rest on the next entry to the enclave.
- static ref SAFETY_BUFFER: SgxMutex = SgxMutex::new(SafetyBuffer::new(16 * 1024, 2 * 1024));
+ static ref SAFETY_BUFFER: SgxMutex = SgxMutex::new(SafetyBuffer::new(4 * 1024, 2 * 1024));
}
static OOM_HAPPENED: AtomicBool = AtomicBool::new(false);
diff --git a/cosmwasm/packages/wasmi-runtime/src/recursion_depth.rs b/cosmwasm/packages/wasmi-runtime/src/recursion_depth.rs
new file mode 100644
index 000000000..8d7e201f9
--- /dev/null
+++ b/cosmwasm/packages/wasmi-runtime/src/recursion_depth.rs
@@ -0,0 +1,55 @@
+use std::sync::SgxMutex;
+
+use lazy_static::lazy_static;
+
+use enclave_ffi_types::EnclaveError;
+
+const RECURSION_LIMIT: u8 = 5;
+
+lazy_static! {
+ /// This counter tracks the recursion depth of queries,
+ /// and effectively the amount of loaded instances of WASMI.
+ ///
+ /// It is incremented before each computation begins and is decremented after each computation ends.
+ static ref RECURSION_DEPTH: SgxMutex = SgxMutex::new(0);
+}
+
+fn increment() -> Result<(), EnclaveError> {
+ let mut depth = RECURSION_DEPTH.lock().unwrap();
+ if *depth == RECURSION_LIMIT {
+ return Err(EnclaveError::ExceededRecursionLimit);
+ }
+ *depth = depth.saturating_add(1);
+ Ok(())
+}
+
+fn decrement() {
+ let mut depth = RECURSION_DEPTH.lock().unwrap();
+ *depth = depth.saturating_sub(1);
+}
+
+/// Returns whether or not this is the last possible level of recursion
+pub fn limit_reached() -> bool {
+ *RECURSION_DEPTH.lock().unwrap() == RECURSION_LIMIT
+}
+
+pub struct RecursionGuard {
+ _private: (), // prevent direct instantiation outside this module
+}
+
+impl RecursionGuard {
+ pub fn new() -> Result {
+ increment()?;
+ Ok(Self { _private: () })
+ }
+}
+
+impl Drop for RecursionGuard {
+ fn drop(&mut self) {
+ decrement();
+ }
+}
+
+pub fn guard() -> Result {
+ RecursionGuard::new()
+}
diff --git a/cosmwasm/packages/wasmi-runtime/src/wasm/query_chain.rs b/cosmwasm/packages/wasmi-runtime/src/wasm/query_chain.rs
index 464833708..ce7656c9c 100644
--- a/cosmwasm/packages/wasmi-runtime/src/wasm/query_chain.rs
+++ b/cosmwasm/packages/wasmi-runtime/src/wasm/query_chain.rs
@@ -1,11 +1,12 @@
use super::errors::WasmEngineError;
use crate::crypto::Ed25519PublicKey;
+use crate::recursion_depth;
use crate::wasm::types::{IoNonce, SecretMessage};
use crate::{exports, imports};
-use crate::cosmwasm::encoding::Binary;
-use crate::cosmwasm::query::{QueryRequest, WasmQuery};
use crate::cosmwasm::{
+ encoding::Binary,
+ query::{QueryRequest, WasmQuery},
std_error::{StdError, StdResult},
system_error::{SystemError, SystemResult},
};
@@ -22,6 +23,10 @@ pub fn encrypt_and_query_chain(
gas_used: &mut u64,
gas_limit: u64,
) -> Result, WasmEngineError> {
+ if let Some(answer) = check_recursion_limit() {
+ return serialize_error_response(&answer);
+ }
+
let mut query_struct: QueryRequest = match serde_json::from_slice(query) {
Ok(query_struct) => query_struct,
Err(err) => {
@@ -182,6 +187,21 @@ fn query_chain(
(Ok(value), gas_used)
}
+/// Check whether the query is allowed to run.
+///
+/// We make sure that a recursion limit is in place in order to
+/// mitigate cases where the enclave runs out of memory.
+fn check_recursion_limit() -> Option>> {
+ if recursion_depth::limit_reached() {
+ debug!(
+ "Recursion limit reached while performing nested queries. Returning error to contract."
+ );
+ Some(Err(SystemError::ExceededRecursionLimit {}))
+ } else {
+ None
+ }
+}
+
fn system_error_invalid_request(request: &[u8], err: T) -> Result, WasmEngineError>
where
T: std::fmt::Debug + ToString,
@@ -196,16 +216,7 @@ where
error: err.to_string(),
});
- serde_json::to_vec(&answer).map_err(|err| {
- // this should never happen
- debug!(
- "encrypt_and_query_chain() got an error while trying to serialize the error {:?} returned to WASM: {:?}",
- answer,
- err
- );
-
- WasmEngineError::SerializationError
- })
+ serialize_error_response(&answer)
}
fn system_error_invalid_response(response: Vec, err: T) -> Result, WasmEngineError>
@@ -217,7 +228,13 @@ where
error: err.to_string(),
});
- serde_json::to_vec(&answer).map_err(|err| {
+ serialize_error_response(&answer)
+}
+
+fn serialize_error_response(
+ answer: &SystemResult>,
+) -> Result, WasmEngineError> {
+ serde_json::to_vec(answer).map_err(|err| {
// this should never happen
debug!(
"encrypt_and_query_chain() got an error while trying to serialize the error {:?} returned to WASM: {:?}",
diff --git a/go-cosmwasm/types/systemerror.go b/go-cosmwasm/types/systemerror.go
index 827cd92b9..bdfd6639e 100644
--- a/go-cosmwasm/types/systemerror.go
+++ b/go-cosmwasm/types/systemerror.go
@@ -12,6 +12,7 @@ type SystemError struct {
NoSuchContract *NoSuchContract `json:"no_such_contract,omitempty"`
Unknown *Unknown `json:"unknown,omitempty"`
UnsupportedRequest *UnsupportedRequest `json:"unsupported_request,omitempty"`
+ ExceededRecursionLimit *ExceededRecursionLimit `json:"exceeded_recursion_limit,omitempty"`
}
var (
@@ -21,6 +22,7 @@ var (
_ error = NoSuchContract{}
_ error = Unknown{}
_ error = UnsupportedRequest{}
+ _ error = ExceededRecursionLimit{}
)
func (a SystemError) Error() string {
@@ -35,6 +37,8 @@ func (a SystemError) Error() string {
return a.Unknown.Error()
case a.UnsupportedRequest != nil:
return a.UnsupportedRequest.Error()
+ case a.ExceededRecursionLimit != nil:
+ return a.ExceededRecursionLimit.Error()
default:
panic("unknown error variant")
}
@@ -80,6 +84,12 @@ func (e UnsupportedRequest) Error() string {
return fmt.Sprintf("unsupported request: %s", e.Kind)
}
+type ExceededRecursionLimit struct{}
+
+func (e ExceededRecursionLimit) Error() string {
+ return "unknown system error"
+}
+
// ToSystemError will try to convert the given error to an SystemError.
// This is important to returning any Go error back to Rust.
//
@@ -118,6 +128,10 @@ func ToSystemError(err error) *SystemError {
return &SystemError{UnsupportedRequest: &t}
case *UnsupportedRequest:
return &SystemError{UnsupportedRequest: t}
+ case ExceededRecursionLimit:
+ return &SystemError{ExceededRecursionLimit: &t}
+ case *ExceededRecursionLimit:
+ return &SystemError{ExceededRecursionLimit: t}
default:
return nil
}
diff --git a/x/compute/internal/keeper/recurse_test.go b/x/compute/internal/keeper/recurse_test.go
index 0d66d833c..7468734b8 100644
--- a/x/compute/internal/keeper/recurse_test.go
+++ b/x/compute/internal/keeper/recurse_test.go
@@ -281,6 +281,7 @@ func TestLimitRecursiveQueryGas(t *testing.T) {
expectedGas uint64
expectOutOfGas bool
expectOOM bool
+ expectRecursionLimit bool
}{
"no recursion, lots of work": {
gasLimit: 4_000_000,
@@ -291,6 +292,18 @@ func TestLimitRecursiveQueryGas(t *testing.T) {
expectQueriesFromContract: 0,
expectedGas: GasWork2k,
},
+ "recursion 4, lots of work": {
+ gasLimit: 4_000_000,
+ msg: Recurse{
+ Depth: 4,
+ Work: 2000,
+ },
+ expectQueriesFromContract: 4,
+ expectedGas: GasWork2k + 9*(GasWork2k+GasReturnHashed),
+ expectOutOfGas: false,
+ expectOOM: false,
+ expectRecursionLimit: false,
+ },
"recursion 9, lots of work": {
gasLimit: 4_000_000,
msg: Recurse{
@@ -300,7 +313,8 @@ func TestLimitRecursiveQueryGas(t *testing.T) {
expectQueriesFromContract: 9,
expectedGas: GasWork2k + 9*(GasWork2k+GasReturnHashed),
expectOutOfGas: false,
- expectOOM: true,
+ expectOOM: false,
+ expectRecursionLimit: true,
},
// this is where we expect an error...
// it has enough gas to run 4 times and die on the 5th (4th time dispatching to sub-contract)
@@ -314,7 +328,8 @@ func TestLimitRecursiveQueryGas(t *testing.T) {
},
expectQueriesFromContract: 4,
expectOutOfGas: false,
- expectOOM: true,
+ expectOOM: false,
+ expectRecursionLimit: true,
},
}
@@ -354,6 +369,14 @@ func TestLimitRecursiveQueryGas(t *testing.T) {
return
}
+ if tc.expectRecursionLimit {
+ _, qErr := queryHelper(t, keeper, ctx, contractAddr, string(msg), true, tc.gasLimit)
+ require.NotEmpty(t, qErr)
+ require.NotNil(t, qErr.GenericErr)
+ require.Contains(t, qErr.GenericErr.Msg, "Querier system error: Query recursion limit exceeded")
+ return
+ }
+
// otherwise, we expect a successful call
_, qErr := queryHelper(t, keeper, ctx, contractAddr, string(msg), true, tc.gasLimit)
require.Empty(t, qErr)
diff --git a/x/compute/internal/keeper/secret_contracts_test.go b/x/compute/internal/keeper/secret_contracts_test.go
index ad2459180..9ec12f178 100644
--- a/x/compute/internal/keeper/secret_contracts_test.go
+++ b/x/compute/internal/keeper/secret_contracts_test.go
@@ -1278,7 +1278,8 @@ func TestMsgSenderInCallback(t *testing.T) {
require.Equal(t, []ContractEvent{
{
{Key: "contract_address", Value: addr.String()},
- {Key: "hi", Value: "hey"}},
+ {Key: "hi", Value: "hey"},
+ },
{
{Key: "contract_address", Value: addr.String()},
{Key: "msg.sender", Value: addr.String()},
@@ -1287,6 +1288,7 @@ func TestMsgSenderInCallback(t *testing.T) {
}
func TestInfiniteQueryLoopKilledGracefullyByOOM(t *testing.T) {
+ t.SkipNow() // We no longer expect to hit OOM trivially
ctx, keeper, tempDir, codeID, codeHash, walletA, privKeyA, _, _ := setupTest(t, "./testdata/test-contract/contract.wasm")
defer os.RemoveAll(tempDir)
@@ -1300,6 +1302,58 @@ func TestInfiniteQueryLoopKilledGracefullyByOOM(t *testing.T) {
require.Equal(t, err.GenericErr.Msg, "query contract failed: Execution error: Enclave: enclave ran out of heap memory")
}
+func TestQueryRecursionLimitEnforcedInQueries(t *testing.T) {
+ ctx, keeper, tempDir, codeID, codeHash, walletA, privKeyA, _, _ := setupTest(t, "./testdata/test-contract/contract.wasm")
+ defer os.RemoveAll(tempDir)
+
+ addr, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, defaultGasForTests)
+ require.Empty(t, err)
+
+ data, err := queryHelper(t, keeper, ctx, addr, fmt.Sprintf(`{"send_external_query_recursion_limit":{"to":"%s","code_hash":"%s", "depth":1}}`, addr.String(), codeHash), true, defaultGasForTests)
+
+ require.NotEmpty(t, data)
+ require.Equal(t, data, "\"Recursion limit was correctly enforced\"")
+
+ require.Nil(t, err.GenericErr)
+}
+
+func TestQueryRecursionLimitEnforcedInHandles(t *testing.T) {
+ ctx, keeper, tempDir, codeID, codeHash, walletA, privKeyA, _, _ := setupTest(t, "./testdata/test-contract/contract.wasm")
+ defer os.RemoveAll(tempDir)
+
+ addr, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, defaultGasForTests)
+ require.Empty(t, err)
+
+ data, _, err := execHelper(t, keeper, ctx, addr, walletA, privKeyA, fmt.Sprintf(`{"send_external_query_recursion_limit":{"to":"%s","code_hash":"%s", "depth":1}}`, addr.String(), codeHash), true, defaultGasForTests, 0)
+
+ require.NotEmpty(t, data)
+ require.Equal(t, string(data), "\"Recursion limit was correctly enforced\"")
+
+ require.Nil(t, err.GenericErr)
+}
+
+func TestQueryRecursionLimitEnforcedInInits(t *testing.T) {
+ ctx, keeper, tempDir, codeID, codeHash, walletA, privKeyA, _, _ := setupTest(t, "./testdata/test-contract/contract.wasm")
+ defer os.RemoveAll(tempDir)
+
+ // Initialize a contract that we will be querying
+ addr, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, defaultGasForTests)
+ require.Empty(t, err)
+
+ // Initialize the contract that will be running the test
+ addr, events, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, fmt.Sprintf(`{"send_external_query_recursion_limit":{"to":"%s","code_hash":"%s", "depth":1}}`, addr.String(), codeHash), true, defaultGasForTests)
+ require.Empty(t, err)
+
+ require.Nil(t, err.GenericErr)
+
+ require.Equal(t, []ContractEvent{
+ {
+ {Key: "contract_address", Value: addr.String()},
+ {Key: "message", Value: "Recursion limit was correctly enforced"},
+ },
+ }, events)
+}
+
func TestWriteToStorageDuringQuery(t *testing.T) {
ctx, keeper, tempDir, codeID, _, walletA, privKeyA, _, _ := setupTest(t, "./testdata/test-contract/contract.wasm")
defer os.RemoveAll(tempDir)
diff --git a/x/compute/internal/keeper/testdata/burner.wasm b/x/compute/internal/keeper/testdata/burner.wasm
index 84d92113a..ed5bbd5e9 100644
Binary files a/x/compute/internal/keeper/testdata/burner.wasm and b/x/compute/internal/keeper/testdata/burner.wasm differ
diff --git a/x/compute/internal/keeper/testdata/contract.wasm b/x/compute/internal/keeper/testdata/contract.wasm
index 053954be2..58fbb1cd0 100644
Binary files a/x/compute/internal/keeper/testdata/contract.wasm and b/x/compute/internal/keeper/testdata/contract.wasm differ
diff --git a/x/compute/internal/keeper/testdata/contract.wasm.gzip b/x/compute/internal/keeper/testdata/contract.wasm.gzip
index 096adb6a5..62388abfc 100644
Binary files a/x/compute/internal/keeper/testdata/contract.wasm.gzip and b/x/compute/internal/keeper/testdata/contract.wasm.gzip differ
diff --git a/x/compute/internal/keeper/testdata/dist.wasm b/x/compute/internal/keeper/testdata/dist.wasm
index 2176d09b5..d8222afd7 100644
Binary files a/x/compute/internal/keeper/testdata/dist.wasm and b/x/compute/internal/keeper/testdata/dist.wasm differ
diff --git a/x/compute/internal/keeper/testdata/erc20.wasm b/x/compute/internal/keeper/testdata/erc20.wasm
index 51a0be32b..80ffeddfb 100644
Binary files a/x/compute/internal/keeper/testdata/erc20.wasm and b/x/compute/internal/keeper/testdata/erc20.wasm differ
diff --git a/x/compute/internal/keeper/testdata/gov.wasm b/x/compute/internal/keeper/testdata/gov.wasm
index 2cd397ece..37eacf599 100644
Binary files a/x/compute/internal/keeper/testdata/gov.wasm and b/x/compute/internal/keeper/testdata/gov.wasm differ
diff --git a/x/compute/internal/keeper/testdata/mint.wasm b/x/compute/internal/keeper/testdata/mint.wasm
index 8486c673e..2daf99564 100644
Binary files a/x/compute/internal/keeper/testdata/mint.wasm and b/x/compute/internal/keeper/testdata/mint.wasm differ
diff --git a/x/compute/internal/keeper/testdata/reflect.wasm b/x/compute/internal/keeper/testdata/reflect.wasm
index 97218d224..9a267b31d 100644
Binary files a/x/compute/internal/keeper/testdata/reflect.wasm and b/x/compute/internal/keeper/testdata/reflect.wasm differ
diff --git a/x/compute/internal/keeper/testdata/staking.wasm b/x/compute/internal/keeper/testdata/staking.wasm
index 4287a2231..2f6709925 100644
Binary files a/x/compute/internal/keeper/testdata/staking.wasm and b/x/compute/internal/keeper/testdata/staking.wasm differ
diff --git a/x/compute/internal/keeper/testdata/test-contract/contract.wasm b/x/compute/internal/keeper/testdata/test-contract/contract.wasm
index 289892cbf..a178c64ff 100644
Binary files a/x/compute/internal/keeper/testdata/test-contract/contract.wasm and b/x/compute/internal/keeper/testdata/test-contract/contract.wasm differ
diff --git a/x/compute/internal/keeper/testdata/test-contract/contract_with_floats.wasm b/x/compute/internal/keeper/testdata/test-contract/contract_with_floats.wasm
index 547e43634..aefde53f9 100644
Binary files a/x/compute/internal/keeper/testdata/test-contract/contract_with_floats.wasm and b/x/compute/internal/keeper/testdata/test-contract/contract_with_floats.wasm differ
diff --git a/x/compute/internal/keeper/testdata/test-contract/src/contract.rs b/x/compute/internal/keeper/testdata/test-contract/src/contract.rs
index 792cdaef0..06661a3a5 100644
--- a/x/compute/internal/keeper/testdata/test-contract/src/contract.rs
+++ b/x/compute/internal/keeper/testdata/test-contract/src/contract.rs
@@ -44,6 +44,11 @@ pub enum InitMsg {
depth: u8,
code_hash: String,
},
+ SendExternalQueryRecursionLimit {
+ to: HumanAddr,
+ depth: u8,
+ code_hash: String,
+ },
CallToInit {
code_id: u64,
code_hash: String,
@@ -171,6 +176,11 @@ pub enum HandleMsg {
code_hash: String,
depth: u8,
},
+ SendExternalQueryRecursionLimit {
+ to: HumanAddr,
+ code_hash: String,
+ depth: u8,
+ },
WithFloats {
x: u8,
y: u8,
@@ -214,6 +224,11 @@ pub enum QueryMsg {
depth: u8,
code_hash: String,
},
+ SendExternalQueryRecursionLimit {
+ to: HumanAddr,
+ depth: u8,
+ code_hash: String,
+ },
CallToQuery {
addr: HumanAddr,
code_hash: String,
@@ -265,6 +280,17 @@ pub fn init(
"",
)],
}),
+ InitMsg::SendExternalQueryRecursionLimit {
+ to,
+ depth,
+ code_hash,
+ } => Ok(InitResponse {
+ messages: vec![],
+ log: vec![log(
+ "message",
+ send_external_query_recursion_limit(deps, to, depth, code_hash)?,
+ )],
+ }),
InitMsg::CallToInit {
code_id,
code_hash,
@@ -457,6 +483,17 @@ pub fn handle(
.into(),
),
}),
+ HandleMsg::SendExternalQueryRecursionLimit {
+ to,
+ code_hash,
+ depth,
+ } => Ok(HandleResponse {
+ messages: vec![],
+ log: vec![],
+ data: Some(to_binary(&send_external_query_recursion_limit(
+ deps, to, depth, code_hash,
+ )?)?),
+ }),
HandleMsg::SendExternalQueryPanic { to, code_hash } => {
send_external_query_panic(deps, to, code_hash)
}
@@ -669,6 +706,45 @@ fn send_external_query_depth_counter(
answer + 1
}
+fn send_external_query_recursion_limit(
+ deps: &Extern,
+ contract_addr: HumanAddr,
+ depth: u8,
+ code_hash: String,
+) -> StdResult {
+ let result = deps
+ .querier
+ .query(&QueryRequest::Wasm(WasmQuery::Smart {
+ contract_addr: contract_addr.clone(),
+ callback_code_hash: code_hash.clone(),
+ msg: Binary(
+ format!(
+ r#"{{"send_external_query_recursion_limit":{{"to":"{}","code_hash":"{}","depth":{}}}}}"#,
+ contract_addr.clone().to_string(),
+ code_hash.clone().to_string(),
+ depth + 1
+ )
+ .into_bytes(),
+ ),
+ }));
+
+ // 5 is the current recursion limit.
+ if depth != 5 {
+ result
+ } else {
+ match result {
+ Err(StdError::GenericErr { msg, .. })
+ if msg == "Querier system error: Query recursion limit exceeded" =>
+ {
+ Ok(String::from("Recursion limit was correctly enforced"))
+ }
+ _ => Err(StdError::generic_err(
+ "Recursion limit was bypassed! this is a bug!",
+ )),
+ }
+ }
+}
+
fn send_external_query_panic(
deps: &mut Extern,
contract_addr: HumanAddr,
@@ -1106,6 +1182,13 @@ pub fn query(
deps, to, depth, code_hash,
))
.unwrap()),
+ QueryMsg::SendExternalQueryRecursionLimit {
+ to,
+ depth,
+ code_hash,
+ } => to_binary(&send_external_query_recursion_limit(
+ deps, to, depth, code_hash,
+ )?),
QueryMsg::CallToQuery {
addr,
code_hash,
diff --git a/x/compute/internal/keeper/testdata/test-contract/static-too-high-initial-memory.wasm b/x/compute/internal/keeper/testdata/test-contract/static-too-high-initial-memory.wasm
index 9bfa97969..f6da6ad28 100644
Binary files a/x/compute/internal/keeper/testdata/test-contract/static-too-high-initial-memory.wasm and b/x/compute/internal/keeper/testdata/test-contract/static-too-high-initial-memory.wasm differ
diff --git a/x/compute/internal/keeper/testdata/test-contract/too-high-initial-memory.wasm b/x/compute/internal/keeper/testdata/test-contract/too-high-initial-memory.wasm
index 51099ccf6..6218dc2f4 100644
Binary files a/x/compute/internal/keeper/testdata/test-contract/too-high-initial-memory.wasm and b/x/compute/internal/keeper/testdata/test-contract/too-high-initial-memory.wasm differ