forked from paritytech/substrate
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
seal_reentrant_count
returns contract reentrant count (paritytech#1…
…2695) * Add logic, test, broken benchmark * account_entrance_count * Addressing comments * Address @agryaznov's comments * Add test for account_entrance_count, fix ci * Cargo fmt * Fix tests * Fix tests * Remove delegated call from test, address comments * Minor fixes and indentation in wat files * Update test for account_entrance_count * Update reentrant_count_call test * Delegate call test * Cargo +nightly fmt * Address comments * Update reentrant_count_works test * Apply weights diff * Add fixture descriptions * Update comments as suggested * Update reentrant_count_call test to use seal_address * add missing code * cargo fmt * account_entrance_count -> account_reentrance_count * fix tests * fmt * normalize signatures Co-authored-by: yarikbratashchuk <yarik.bratashchuk@gmail.com>
- Loading branch information
Showing
10 changed files
with
569 additions
and
1 deletion.
There are no files selected for viewing
37 changes: 37 additions & 0 deletions
37
frame/contracts/fixtures/account_reentrance_count_call.wat
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,37 @@ | ||
;; This fixture tests if account_reentrance_count works as expected | ||
;; testing it with 2 different addresses | ||
(module | ||
(import "seal0" "seal_input" (func $seal_input (param i32 i32))) | ||
(import "seal0" "seal_caller" (func $seal_caller (param i32 i32))) | ||
(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32))) | ||
(import "__unstable__" "account_reentrance_count" (func $account_reentrance_count (param i32) (result i32))) | ||
(import "env" "memory" (memory 1 1)) | ||
|
||
;; [0, 32) buffer where input is copied | ||
;; [32, 36) size of the input buffer | ||
(data (i32.const 32) "\20") | ||
|
||
(func $assert (param i32) | ||
(block $ok | ||
(br_if $ok | ||
(get_local 0) | ||
) | ||
(unreachable) | ||
) | ||
) | ||
|
||
(func (export "call") | ||
;; Reading "callee" input address | ||
(call $seal_input (i32.const 0) (i32.const 32)) | ||
|
||
(i32.store | ||
(i32.const 36) | ||
(call $account_reentrance_count (i32.const 0)) | ||
) | ||
|
||
(call $seal_return (i32.const 0) (i32.const 36) (i32.const 4)) | ||
) | ||
|
||
(func (export "deploy")) | ||
|
||
) |
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,76 @@ | ||
;; This fixture recursively tests if reentrant_count returns correct reentrant count value when | ||
;; using seal_call to make caller contract call to itself | ||
(module | ||
(import "seal0" "seal_input" (func $seal_input (param i32 i32))) | ||
(import "seal0" "seal_address" (func $seal_address (param i32 i32))) | ||
(import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) | ||
(import "__unstable__" "reentrant_count" (func $reentrant_count (result i32))) | ||
(import "env" "memory" (memory 1 1)) | ||
|
||
;; [0, 32) reserved for $seal_address output | ||
|
||
;; [32, 36) buffer for the call stack height | ||
|
||
;; [36, 40) size of the input buffer | ||
(data (i32.const 36) "\04") | ||
|
||
;; [40, 44) length of the buffer for $seal_address | ||
(data (i32.const 40) "\20") | ||
|
||
(func $assert (param i32) | ||
(block $ok | ||
(br_if $ok | ||
(get_local 0) | ||
) | ||
(unreachable) | ||
) | ||
) | ||
(func (export "call") | ||
(local $expected_reentrant_count i32) | ||
(local $seal_call_exit_code i32) | ||
|
||
;; reading current contract address | ||
(call $seal_address (i32.const 0) (i32.const 40)) | ||
|
||
;; reading passed input | ||
(call $seal_input (i32.const 32) (i32.const 36)) | ||
|
||
;; reading manually passed reentrant count | ||
(set_local $expected_reentrant_count (i32.load (i32.const 32))) | ||
|
||
;; reentrance count is calculated correctly | ||
(call $assert | ||
(i32.eq (call $reentrant_count) (get_local $expected_reentrant_count)) | ||
) | ||
|
||
;; re-enter 5 times in a row and assert that the reentrant counter works as expected | ||
(i32.eq (call $reentrant_count) (i32.const 5)) | ||
(if | ||
(then) ;; recursion exit case | ||
(else | ||
;; incrementing $expected_reentrant_count passed to the contract | ||
(i32.store (i32.const 32) (i32.add (i32.load (i32.const 32)) (i32.const 1))) | ||
|
||
;; Call to itself | ||
(set_local $seal_call_exit_code | ||
(call $seal_call | ||
(i32.const 8) ;; Allow reentrancy flag set | ||
(i32.const 0) ;; Pointer to "callee" address | ||
(i64.const 0) ;; How much gas to devote for the execution. 0 = all. | ||
(i32.const 0) ;; Pointer to the buffer with value to transfer | ||
(i32.const 32) ;; Pointer to input data buffer address | ||
(i32.const 4) ;; Length of input data buffer | ||
(i32.const 0xffffffff) ;; u32 max sentinel value: do not copy output | ||
(i32.const 0) ;; Ptr to output buffer len | ||
) | ||
) | ||
|
||
(call $assert | ||
(i32.eq (get_local $seal_call_exit_code) (i32.const 0)) | ||
) | ||
) | ||
) | ||
) | ||
|
||
(func (export "deploy")) | ||
) |
71 changes: 71 additions & 0 deletions
71
frame/contracts/fixtures/reentrant_count_delegated_call.wat
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,71 @@ | ||
;; This fixture recursively tests if reentrant_count returns correct reentrant count value when | ||
;; using seal_delegate_call to make caller contract delegate call to itself | ||
(module | ||
(import "seal0" "seal_input" (func $seal_input (param i32 i32))) | ||
(import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32))) | ||
(import "seal0" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32))) | ||
(import "__unstable__" "reentrant_count" (func $reentrant_count (result i32))) | ||
(import "env" "memory" (memory 1 1)) | ||
|
||
;; [0, 32) buffer where code hash is copied | ||
|
||
;; [32, 36) buffer for the call stack height | ||
|
||
;; [36, 40) size of the input buffer | ||
(data (i32.const 36) "\24") | ||
|
||
(func $assert (param i32) | ||
(block $ok | ||
(br_if $ok | ||
(get_local 0) | ||
) | ||
(unreachable) | ||
) | ||
) | ||
(func (export "call") | ||
(local $callstack_height i32) | ||
(local $delegate_call_exit_code i32) | ||
|
||
;; Reading input | ||
(call $seal_input (i32.const 0) (i32.const 36)) | ||
|
||
;; reading passed callstack height | ||
(set_local $callstack_height (i32.load (i32.const 32))) | ||
|
||
;; incrementing callstack height | ||
(i32.store (i32.const 32) (i32.add (i32.load (i32.const 32)) (i32.const 1))) | ||
|
||
;; reentrance count stays 0 | ||
(call $assert | ||
(i32.eq (call $reentrant_count) (i32.const 0)) | ||
) | ||
|
||
(i32.eq (get_local $callstack_height) (i32.const 5)) | ||
(if | ||
(then) ;; exit recursion case | ||
(else | ||
;; Call to itself | ||
(set_local $delegate_call_exit_code | ||
(call $seal_delegate_call | ||
(i32.const 0) ;; Set no call flags | ||
(i32.const 0) ;; Pointer to "callee" code_hash. | ||
(i32.const 0) ;; Pointer to the input data | ||
(i32.const 36) ;; Length of the input | ||
(i32.const 4294967295) ;; u32 max sentinel value: do not copy output | ||
(i32.const 0) ;; Length is ignored in this case | ||
) | ||
) | ||
|
||
(call $assert | ||
(i32.eq (get_local $delegate_call_exit_code) (i32.const 0)) | ||
) | ||
) | ||
) | ||
|
||
(call $assert | ||
(i32.le_s (get_local $callstack_height) (i32.const 5)) | ||
) | ||
) | ||
|
||
(func (export "deploy")) | ||
) |
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
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
Oops, something went wrong.