1
0
mirror of https://github.com/danog/toncontest.git synced 2024-11-26 12:04:50 +01:00

Final test suite

This commit is contained in:
Daniil Gentili 2019-10-15 00:17:30 +02:00
parent 84edf128a3
commit d902bc1ec3
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
5 changed files with 316 additions and 4 deletions

242
toolchain/gen-zerostate.fif Normal file
View File

@ -0,0 +1,242 @@
"TonUtil.fif" include
"Asm.fif" include
def? $1 { @' $1 } { "" } cond constant suffix
{ suffix $+ } : +suffix
wc_master setworkchain
-17 setglobalid // negative value means a test instance of the blockchain
// Initial state of Workchain 0 (Basic workchain)
0 mkemptyShardState
cr ."initial basechain state is:" cr dup <s csr. cr
dup dup 31 boc+>B dup Bx. cr
dup "basestate0" +suffix +".boc" tuck B>file
."(Initial basechain state saved to file " type .")" cr
Bhashu dup =: basestate0_fhash
."file hash=" dup x. space 256 u>B dup B>base64url type cr
"basestate0" +suffix +".fhash" B>file
hashu dup =: basestate0_rhash
."root hash=" dup x. space 256 u>B dup B>base64url type cr
"basestate0" +suffix +".rhash" B>file
basestate0_rhash basestate0_fhash now 0 2 32 0 add-std-workchain
config.workchains!
// SmartContract #1 (Simple wallet)
<{ SETCP0 DUP IFNOTRET // return if recv_internal
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
DROP c4 PUSHCTR CTOS 32 PLDU // cnt
}>
INC 32 THROWIF // fail unless recv_external
512 INT LDSLICEX DUP 32 PLDU // sign cs cnt
c4 PUSHCTR CTOS 32 LDU 256 LDU ENDS // sign cs cnt cnt' pubk
s1 s2 XCPU // sign cs cnt pubk cnt' cnt
EQUAL 33 THROWIFNOT // ( seqno mismatch? )
s2 PUSH HASHSU // sign cs cnt pubk hash
s0 s4 s4 XC2PU // pubk cs cnt hash sign pubk
CHKSIGNU // pubk cs cnt ?
34 THROWIFNOT // signature mismatch
ACCEPT
SWAP 32 LDU NIP 8 LDU LDREF ENDS // pubk cnt mode msg
SWAP SENDRAWMSG // pubk cnt ; ( message sent )
INC NEWC 32 STU 256 STU ENDC c4 POPCTR
}>c
// code
<b 0 32 u,
"main-wallet" +suffix +".pk" load-generate-keypair drop
B,
b> // data
Libs{
x{ABACABADABACABA} s>c public_lib
x{1234} x{5678} |_ s>c private_lib
}Libs // libraries
GR$1700000000 // balance
0 // split_depth
0 // ticktock
2 // mode: create
register_smc
dup make_special dup constant smc1_addr
Masterchain over
2dup ."wallet address = " .addr cr 2dup 6 .Addr cr
"main-wallet" +suffix +".addr" save-address-verbose
// SmartContract #2 (Simple money giver for test network)
<{ SETCP0 DUP IFNOTRET // return if recv_internal
DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method
DROP c4 PUSHCTR CTOS 32 PLDU // cnt
}>
INC 32 THROWIF // fail unless recv_external
32 LDU SWAP // cs cnt
c4 PUSHCTR CTOS 32 LDU ENDS // cs cnt cnt'
TUCK EQUAL 33 THROWIFNOT // ( seqno mismatch? )
ACCEPT // cs cnt'
SWAP 8 LDU LDREF ENDS // cnt'' mode msg
GR$20 INT 3 INT RAWRESERVE // reserve all but 20 Grams from the balance
SWAP SENDRAWMSG
INC NEWC 32 STU ENDC c4 POPCTR // store cnt''
}>c
// code
<b 0 32 u, b> // data
empty_cell // libraries
GR$1000000 // initial balance (1m test Grams)
0 0 2 register_smc
dup make_special dup constant smc2_addr
Masterchain over
2dup ."free test gram giver address = " .addr cr 2dup 6 .Addr cr
"testgiver" +suffix +".addr" save-address-verbose
// SmartContract #3
PROGRAM{
recv_internal x{} PROC
run_ticktock PROC:<{
c4 PUSHCTR CTOS 32 LDU 256 LDU ENDS
NEWC ROT INC 32 STUR OVER 256 STUR ENDC
c4 POPCTR
// first 32 bits of persistent data have been increased
// remaining 256 bits with an address have been fetched
// create new empty message with 0.1 Grams to that address
NEWC b{00100010011111111} STSLICECONST TUCK 256 STU
100000000 INT STGRAMS // store 0.1 Grams
1 4 + 4 + 64 + 32 + 1+ 1+ INT STZEROES ENDC
// send raw message from Cell
ZERO SENDRAWMSG
-17 INT 256 STIR 130000000 INT STGRAMS
107 INT STZEROES ENDC
ZERO // another message with 0.13 Grams to account -17
NEWC b{11000100100000} "test" $>s |+ STSLICECONST
123456789 INT STGRAMS
107 INT STZEROES "Hello, world!" $>s STSLICECONST ENDC
ZERO SENDRAWMSG SENDRAWMSG // external message to address "test"
}>
}END>c
// code
<b x{11EF55AA} s, smc1_addr 256 u, b> // data
// empty_cell // libraries
Libs{
x{ABACABADABACABA} s>c public_lib
x{1234} x{5678} |_ s>c public_lib
}Libs // libraries
0x333333333 // balance
0 // split_depth
3 // ticktock: tick
2 // mode: create
register_smc
dup make_special dup constant smc3_addr
."address = " x. cr
/*
*
* SmartContract #4 (elector)
*
*/
"elector-code.fif" include // code in separate source file
<b 0 1 1+ 1+ 4 + 32 + u, 0 256 u, b> // data: dict dict dict grams uint32 uint256
empty_cell // libraries
GR$10 // balance: 10 grams
0 // split_depth
2 // ticktock: tick
2 // mode: create
register_smc
dup make_special dup constant smc4_addr dup constant elector_addr
Masterchain swap
."elector smart contract address = " 2dup .addr cr 2dup 7 .Addr cr
"elector" +suffix +".addr" save-address-verbose
/*
*
* Configuration Parameters
*
*/
// version capabilities
0 capCreateStats config.version!
// max-validators max-main-validators min-validators
// 9 4 1 config.validator_num!
1000 100 5 config.validator_num!
// min-stake max-stake min-total-stake max-factor
GR$10000 GR$10000000 GR$1000000 sg~10 config.validator_stake_limits!
// elected-for elect-start-before elect-end-before stakes-frozen-for
// 400000 200000 4000 400000 config.election_params!
4000 2000 500 1000 config.election_params! // DEBUG
// config-addr = -1:5555...5555
256 1<<1- 3 / constant config_addr
config_addr config.config_smc!
// elector-addr
elector_addr config.elector_smc!
// 1 sg* 100 sg* 1000 sg* 1000000 sg* config.storage_prices! // old values (too high)
1 500 1000 500000 config.storage_prices!
config.special!
// gas_price gas_limit special_gas_limit gas_credit block_gas_limit freeze_due_limit delete_due_limit flat_gas_limit flat_gas_price --
1000 sg* 1 *M dup 10000 10 *M GR$0.1 GR$1.0 100 100000 config.gas_prices!
10000 sg* 1 *M 10 *M 10000 10 *M GR$0.1 GR$1.0 100 1000000 config.mc_gas_prices!
// lump_price bit_price cell_price ihr_factor first_frac next_frac
1000000 1000 sg* 100000 sg* 3/2 sg*/ 1/3 sg*/ 1/3 sg*/ config.fwd_prices!
10000000 10000 sg* 1000000 sg* 3/2 sg*/ 1/3 sg*/ 1/3 sg*/ config.mc_fwd_prices!
// mc-cc-lifetime sh-cc-lifetime sh-val-lifetime sh-val-num
250 250 1000 7 config.catchain_params!
// round-candidates next-cand-delay-ms consensus-timeout-ms fast-attempts attempt-duration cc-max-deps max-block-size max-collated-size
3 2000 16000 3 8 4 2 *Mi 2 *Mi config.consensus_params!
128 *Ki 512 *Ki 1 *Mi triple // [ underload soft hard ] : block bytes limit
100000 500000 1000000 triple // gas limits
1000 5000 10000 triple // lt limits
triple dup untriple config.mc_block_limits!
untriple config.block_limits!
GR$1.7 GR$1 config.block_create_fees!
// smc1_addr config.collector_smc!
smc1_addr config.minter_smc!
1000000000000 -17 of-cc 666666666666 239 of-cc cc+ config.to_mint!
"validator-keys" +suffix +".pk" load-generate-keypair drop
{ dup Blen } { 32 B| swap dup ."Validator public key = " Bx. cr
17 add-validator } while drop
// newkeypair nip dup ."Validator #1 public key = " Bx. cr
// 17 add-validator
// newkeypair nip dup ."Validator #2 public key = " Bx. cr
// 239 add-validator
// 100000 =: orig_vset_valid_for
100 =: orig_vset_valid_for // original validator set valid 100 seconds only (DEBUG)
now dup orig_vset_valid_for + 0 config.validators!
/*
*
* SmartContract #5 (Configuration smart contract)
*
*/
"config-code.fif" include // code in separate source file
<b 0 32 u,
"config-master" +suffix +".pk" load-generate-keypair drop
B,
configdict ref,
b> // data
empty_cell // libraries
GR$10 // balance
0 1 config_addr 6 register_smc // tock
dup set_config_smc
Masterchain swap
."config smart contract address = " 2dup .addr cr 2dup 7 .Addr cr
"config-master" +suffix +".addr" save-address-verbose
// Other data
create_state
cr cr ."new state is:" cr dup <s csr. cr
dup 31 boc+>B dup Bx. cr
dup "zerostate" +suffix +".boc" tuck B>file
."(Initial masterchain state saved to file " type .")" cr
Bhashu dup =: zerostate_fhash
."file hash= " dup X. space 256 u>B dup B>base64url type cr
"zerostate" +suffix +".fhash" B>file
hashu dup =: zerostate_rhash ."root hash= " dup X. space 256 u>B dup B>base64url type cr
"zerostate" +suffix +".rhash" B>file
basestate0_rhash ."Basestate0 root hash= " dup X. space 256 u>B B>base64url type cr
basestate0_fhash ."Basestate0 file hash= " dup X. space 256 u>B B>base64url type cr
zerostate_rhash ."Zerostate root hash= " dup X. space 256 u>B B>base64url type cr
zerostate_fhash ."Zerostate file hash= " dup X. space 256 u>B B>base64url type cr

35
toolchain/testgiver.fif Executable file
View File

@ -0,0 +1,35 @@
#!/usr/bin/fift -s
"TonUtil.fif" include
{ ."usage: " @' $0 type ." <dest-addr> <seqno> <amount> [<savefile>]" cr
."Creates a request to TestGiver and saves it into <savefile>.boc" cr
."('testgiver-query.boc' by default)" cr 1 halt
} : usage
$# 3 - -2 and ' usage if
"testgiver.addr" load-address
// Masterchain 0xfcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260
2constant giver_addr
."Test giver address = " giver_addr 2dup .addr cr 6 .Addr cr
$1 true parse-load-address =: bounce 2=: dest_addr
$2 parse-int =: seqno
$3 $>GR =: amount
def? $4 { @' $4 } { "testgiver-query" } cond constant savefile
."Requesting " amount .GR ."to account "
dest_addr 2dup bounce 7 + .Addr ." = " .addr
."seqno=0x" seqno x. ."bounce=" bounce . cr
// create a message (NB: 01b00.., b = bounce)
<b b{01} s, bounce 1 i, b{000100} s, dest_addr addr,
amount Gram, 0 9 64 32 + + 1+ 1+ u, 0 32 u, "GIFT" $, b>
<b seqno 32 u, 1 8 u, swap ref, b>
dup ."enveloping message: " <s csr. cr
<b b{1000100} s, giver_addr addr, 0 Gram, b{00} s,
swap <s s, b>
dup ."resulting external message: " <s csr. cr
2 boc+>B dup Bx. cr
savefile +".boc" tuck B>file
."(Saved to file " type .")" cr

View File

@ -6,12 +6,11 @@ Upgradable multisignature wallet, with custom scripts to deserialize and inspect
All custom data structures used in the wallet can be viewed as a custom TL-B scheme in `proto/scheme.tlb` (some basic TON constructors are also included for reference).
Most smart contact get-methods (except for the basic seqno and getPartials methods) return an integer, indicating whether the operation was successful and the requested data was found, followed by a cell/integer with the found data (or an empty cell/0 in case of failure).
I've been having some issues generating a TON zerostate in order to test my contract using `test-ton-collator`, which is why I have created a full testing platform with a collator emulator in FIFT that parses the generated external messages and runs the required logic (including code and data initialization from the StateInit of constructor messages, with support for multiple consecutive method calls and data persistence) in the TVM, fully emulating the logic of `Transaction::unpack_input_msg` and `Collator::create_ordinary_transaction`.
I created a full testing platform with a collator emulator in FIFT that parses the generated external messages and runs the required logic (including code and data initialization from the StateInit of constructor messages, with support for multiple consecutive method calls and data persistence) in the TVM, partially emulating the logic of `Transaction::unpack_input_msg` and `Collator::create_ordinary_transaction`.
I have rechecked the validity of generated BOC files against the TL-B schemes for blockchain messages, and everything seems to work in my offchain test suite, but my messages (at least the constructor messages) aren't accepted by the testnet: I've tried using the `test-ton-collator` program to simulate the workflow (and get logs!) of the collators that reject my messages, but I encountered problems with the creation of a zerostate for the blockchain collator, explained in detail in issue [#144](https://github.com/ton-blockchain/ton/issues/144).
I've tested throughly the smart contract using my local collator emulator (`test.fif`), but I couldn't get the actual TON collator to start due to missing documentation.
I've tested throughly the smart contract using my local collator emulator (`test.fif`), and the actual TON collator using a slightly tweaked [zerostate generator](https://github.com/ton-blockchain/ton/pull/145) and the custom `test-collator.sh` script.
Anyway, I had loads of fun working with funC and especially fift, and I'm really looking forward to building stuff on TON; especially TON services on the P2P ADNL network, I'll start by adding support for the ADNL protocol in my MTProto client, [MadelineProto](https://github.com/danog/MadelineProto); but I'll also experiment more with the TON blockchain, creating s'more smart contracts.
I had loads of fun working with funC and especially fift, and I'm really looking forward to building stuff on TON; especially TON services on the P2P ADNL network, I'll start by adding support for the ADNL protocol in my MTProto client, [MadelineProto](https://github.com/danog/MadelineProto); but I'll also experiment more with the TON blockchain, creating s'more smart contracts.
## Project structure
@ -189,3 +188,15 @@ fift -s ../test.fif \
If we were running on the blockchain, at this point the smart contract code root would be updated to point to the new code, allowing us to use the new `getMagic` (77784) method that returns (420, 69) when called.
Since we're running in a local TVM instance, and fift's `runvm` primitives have no way of returning the output action list (including changes to the code), the code isn't actually updated, but the modified signature list and minSig data structures in the persistent contract storage are indeed returned to the fift stack and re-used for the next TVM method call, allowing us to test the feature.
## Collator testing
After running `test.sh` and `test-update.sh` (thus generating all BOC files), you can run the `test-collator.sh` script, to:
* Automatically configure a TON collator instance
* Make a query to the testgiver on the local collator instance
* Load the wallet smart contract
* Load a query with 2 signatures (`a`, `b`)
* Upgrade the smart contract to accept 3 signatures
* Load one more signature and send the message

22
wallet/test-collator.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/bash -ex
{
address=$(cat tests/naddr.addr)
cd ../lib/build
rm -rf new
mkdir -p new
cd new
mkdir -p db/static
../crypto/create-state ../../../toolchain/gen-zerostate.fif | tee log
mv basestate0.boc db/static/$(sed '/Basestate0 file hash= /!d;s/Basestate0 file hash= //g;s/ .*//g' log)
cp zerostate.boc db/static/$(sed '/Zerostate file hash= /!d;s/Zerostate file hash= //g;s/ .*//g' log)
rm log
fift -s ../../../toolchain/testgiver.fif $address 0 20
../test-ton-collator -z zerostate.boc -D db -v5 -m testgiver-query.boc
../test-ton-collator -z zerostate.boc -D db -v5 -w 0 -m ../../../wallet/tests/pony-create.boc -m ../../../wallet/tests/b.boc -m ../../../wallet/tests/code-update-merge.boc -m ../../../wallet/tests/c.boc
} 2>&1 | less -R

View File

@ -13,6 +13,8 @@ for f in {a..j}; do fift -s ../gen-pub.fif $f;done
fift -s ../wallet-create.fif 0 pony 10 10 {a..j} | tee log
# Get wallet address
sed '/Non-bounceable address [(]for init[)]: /!d;s/.* //g' log > naddr.addr
address=$(sed '/Bounceable address [(]for later access[)]: /!d;s/.* //g' log)
rm log