mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
pow-testgiver support
This commit is contained in:
parent
dbde9c1c40
commit
f064b1047a
257 changed files with 6665 additions and 2608 deletions
59
crypto/smartcont/new-pow-testgiver.fif
Normal file
59
crypto/smartcont/new-pow-testgiver.fif
Normal file
|
@ -0,0 +1,59 @@
|
|||
#!/usr/bin/fift -s
|
||||
"TonUtil.fif" include
|
||||
"Asm.fif" include
|
||||
|
||||
{ ."usage: " $0 type ." <workchain-id> <giver-id> <amount> <interval> <min-complexity> <init-complexity> <max-complexity> [<filename-base>]" cr
|
||||
."Creates a new proof-of-work testgiver with unique 32-bit identifier <giver-id> designed to deliver <amount> every <interval> seconds, with SHA256 hash complexity between 2**<min-complexity> and 2**<max-complexity>, with private key saved to or loaded from <filename-base>.pk" cr
|
||||
."('pow-giver.pk' by default)" cr 1 halt
|
||||
} : usage
|
||||
$# 7 - -2 and ' usage if
|
||||
|
||||
8 :$1..n
|
||||
$1 parse-workchain-id =: wc // set workchain id from command line argument
|
||||
$2 parse-int dup =: subwallet-id
|
||||
0= abort"giver-id must be non-zero"
|
||||
$3 $>GR =: amount
|
||||
$4 parse-int dup =: interval
|
||||
dup 24 ufits and 0= abort"invalid interval"
|
||||
$5 parse-int dup =: min-cpl
|
||||
1- 8 ufits not abort"invalid minimal log-complexity (must be 1..256)"
|
||||
$6 parse-int dup =: init-cpl
|
||||
1- 8 ufits not abort"invalid initial log-complexity (must be 1..256)"
|
||||
$7 parse-int dup =: max-cpl
|
||||
1- 8 ufits not abort"invalid maximal log-complexity (must be 1..256)"
|
||||
$8 "pow-giver" replace-if-null =: file-base
|
||||
|
||||
min-cpl init-cpl > abort"initial complexity cannot be below minimal complexity"
|
||||
max-cpl init-cpl < abort"initial complexity cannot exceed maximal complexity"
|
||||
subwallet-id (.) 1 ' $+ does : +subwallet
|
||||
|
||||
."Creating new proof-of-work testgiver in workchain " wc .
|
||||
."with unique giver id " subwallet-id . cr
|
||||
."Designed to give " amount .GR ."approximately every " interval . ."seconds" cr
|
||||
."Complexity (in SHA256 hashes): min=" min-cpl 1<< . ."init=" init-cpl 1<< . ."max=" max-cpl 1<< . cr
|
||||
|
||||
"auto/pow-testgiver-code.fif" include // code
|
||||
{ 256 swap - 8 u, } : cpl,
|
||||
<b 0 32 u, subwallet-id 32 u, // seqno wallet-id
|
||||
file-base +".pk" load-generate-keypair constant wallet_pk B, // pubkey
|
||||
newkeypair nip 16 B| drop B, // seed
|
||||
256 init-cpl - 1<< 256 u, // pow_complexity
|
||||
-1 32 i, // last_success
|
||||
<b amount Gram, interval 32 u, max-cpl cpl, min-cpl cpl, b> ref,
|
||||
b> // data
|
||||
null // no libraries
|
||||
<b b{0011} s, 3 roll ref, rot ref, swap dict, b> // create StateInit
|
||||
dup ."StateInit: " <s csr. cr
|
||||
dup hashu wc swap 2dup 2constant wallet_addr
|
||||
."new PoW testgiver address = " 2dup .addr cr
|
||||
2dup file-base +subwallet +".addr" save-address-verbose
|
||||
."Non-bounceable address (for init): " 2dup 7 .Addr cr
|
||||
."Bounceable address (for later access): " 6 .Addr cr
|
||||
<b subwallet-id 32 u, -1 32 i, 0 32 u, b>
|
||||
dup ."signing message: " <s csr. cr
|
||||
dup hashu wallet_pk ed25519_sign_uint rot
|
||||
<b b{1000100} s, wallet_addr addr, b{000010} s, swap <s s, b{0} s, swap B, swap <s s, b>
|
||||
dup ."External message for initialization is " <s csr. cr
|
||||
2 boc+>B dup Bx. cr
|
||||
file-base +subwallet +"-query.boc" tuck B>file
|
||||
."(Saved proof-of-work testgiver creating query to file " type .")" cr
|
158
crypto/smartcont/pow-testgiver-code.fc
Normal file
158
crypto/smartcont/pow-testgiver-code.fc
Normal file
|
@ -0,0 +1,158 @@
|
|||
;; Advanced TestGiver smart contract with Proof-of-Work verification
|
||||
|
||||
int ufits(int x, int bits) impure asm "UFITSX";
|
||||
|
||||
() recv_internal(slice in_msg) impure {
|
||||
;; do nothing for internal messages
|
||||
}
|
||||
|
||||
() check_proof_of_work(slice cs) impure inline_ref {
|
||||
var hash = slice_hash(cs);
|
||||
var ds = get_data().begin_parse();
|
||||
var (stored_seqno_sw, public_key, seed, pow_complexity) = (ds~load_uint(64), ds~load_uint(256), ds~load_uint(128), ds~load_uint(256));
|
||||
throw_unless(24, hash < pow_complexity); ;; hash problem NOT solved
|
||||
var (op, flags, expire, whom, rdata1, rseed, rdata2) = (cs~load_uint(32), cs~load_int(8), cs~load_uint(32), cs~load_uint(256), cs~load_uint(256), cs~load_uint(128), cs~load_uint(256));
|
||||
cs.end_parse();
|
||||
ufits(expire - now(), 10);
|
||||
throw_unless(25, (rseed == seed) & (rdata1 == rdata2));
|
||||
;; Proof of Work correct
|
||||
accept_message();
|
||||
randomize_lt();
|
||||
randomize(rdata1);
|
||||
var (last_success, xdata) = (ds~load_uint(32), ds~load_ref());
|
||||
ds.end_parse();
|
||||
ds = xdata.begin_parse();
|
||||
var (amount, target_delta, min_cpl, max_cpl) = (ds~load_grams(), ds~load_uint(32), ds~load_uint(8), ds~load_uint(8));
|
||||
ds.end_parse();
|
||||
;; recompute complexity
|
||||
int delta = now() - last_success;
|
||||
if (delta > 0) {
|
||||
int factor = muldivr(delta, 1 << 128, target_delta);
|
||||
factor = min(max(factor, 7 << 125), 9 << 125); ;; factor must be in range 7/8 .. 9/8
|
||||
pow_complexity = muldivr(pow_complexity, factor, 1 << 128); ;; rescale complexity
|
||||
pow_complexity = min(max(pow_complexity, 1 << min_cpl), 1 << max_cpl);
|
||||
}
|
||||
;; update data
|
||||
set_data(begin_cell()
|
||||
.store_uint(stored_seqno_sw, 64)
|
||||
.store_uint(public_key, 256)
|
||||
.store_uint(random() >> 128, 128) ;; new seed
|
||||
.store_uint(pow_complexity, 256)
|
||||
.store_uint(now(), 32) ;; new last_success
|
||||
.store_ref(xdata)
|
||||
.end_cell());
|
||||
commit();
|
||||
;; create outbound message
|
||||
send_raw_message(begin_cell()
|
||||
.store_uint(((flags & 1) << 6) | 0x84, 9)
|
||||
.store_int(flags >> 2, 8)
|
||||
.store_uint(whom, 256)
|
||||
.store_grams(amount)
|
||||
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
|
||||
.end_cell(), 3);
|
||||
}
|
||||
|
||||
() rescale_complexity(slice cs) impure inline_ref {
|
||||
var (op, expire) = (cs~load_uint(32), cs~load_uint(32));
|
||||
cs.end_parse();
|
||||
int time = now();
|
||||
throw_unless(28, time > expire);
|
||||
var ds = get_data().begin_parse();
|
||||
var (skipped_data, pow_complexity, last_success, xdata) = (ds~load_bits(64 + 256 + 128), ds~load_uint(256), ds~load_uint(32), ds~load_ref());
|
||||
ds.end_parse();
|
||||
throw_unless(29, expire > last_success);
|
||||
ds = xdata.begin_parse();
|
||||
var (amount, target_delta) = (ds~load_grams(), ds~load_uint(32));
|
||||
int delta = time - last_success;
|
||||
throw_unless(30, delta >= target_delta * 16);
|
||||
accept_message();
|
||||
var (min_cpl, max_cpl) = (ds~load_uint(8), ds~load_uint(8));
|
||||
ds.end_parse();
|
||||
int factor = muldivr(delta, 1 << 128, target_delta);
|
||||
int max_complexity = (1 << max_cpl);
|
||||
int max_factor = muldiv(max_complexity, 1 << 128, pow_complexity);
|
||||
pow_complexity = (max_factor < factor ? max_complexity : muldivr(pow_complexity, factor, 1 << 128));
|
||||
last_success = time - target_delta;
|
||||
set_data(begin_cell()
|
||||
.store_slice(skipped_data)
|
||||
.store_uint(pow_complexity, 256)
|
||||
.store_uint(last_success, 32) ;; new last_success
|
||||
.store_ref(xdata)
|
||||
.end_cell());
|
||||
}
|
||||
|
||||
(slice, ()) ~update_params(slice ds, cell pref) inline_ref {
|
||||
var cs = pref.begin_parse();
|
||||
var reset_cpl = cs~load_uint(8);
|
||||
var (seed, pow_complexity, last_success) = (ds~load_uint(128), ds~load_uint(256), ds~load_uint(32));
|
||||
if (reset_cpl) {
|
||||
randomize(seed);
|
||||
pow_complexity = (1 << reset_cpl);
|
||||
seed = (random() >> 128);
|
||||
}
|
||||
var c = begin_cell()
|
||||
.store_uint(seed, 128)
|
||||
.store_uint(pow_complexity, 256)
|
||||
.store_uint(now(), 32)
|
||||
.store_ref(begin_cell().store_slice(cs).end_cell())
|
||||
.end_cell();
|
||||
return (begin_parse(c), ());
|
||||
}
|
||||
|
||||
() recv_external(slice in_msg) impure {
|
||||
var op = in_msg.preload_uint(32);
|
||||
if (op == 0x4d696e65) {
|
||||
;; Mine = Obtain test grams by presenting valid proof of work
|
||||
return check_proof_of_work(in_msg);
|
||||
}
|
||||
if (op == 0x5253636c) {
|
||||
;; RScl = Rescale complexity if no success for long time
|
||||
return rescale_complexity(in_msg);
|
||||
}
|
||||
var signature = in_msg~load_bits(512);
|
||||
var cs = in_msg;
|
||||
var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));
|
||||
throw_if(35, valid_until <= now());
|
||||
var ds = get_data().begin_parse();
|
||||
var (stored_seqno, stored_subwallet, public_key) = (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256));
|
||||
throw_unless(33, msg_seqno == stored_seqno);
|
||||
throw_unless(34, (subwallet_id == stored_subwallet) | (subwallet_id == 0));
|
||||
throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));
|
||||
accept_message();
|
||||
cs~touch();
|
||||
while (cs.slice_refs()) {
|
||||
var ref = cs~load_ref();
|
||||
var mode = cs~load_uint(8);
|
||||
if (mode < 0xff) {
|
||||
send_raw_message(ref, mode);
|
||||
} else {
|
||||
ds~update_params(ref);
|
||||
}
|
||||
}
|
||||
set_data(begin_cell()
|
||||
.store_uint(stored_seqno + 1, 32)
|
||||
.store_uint(stored_subwallet, 32)
|
||||
.store_uint(public_key, 256)
|
||||
.store_slice(ds)
|
||||
.end_cell());
|
||||
}
|
||||
|
||||
;; Get methods
|
||||
|
||||
int seqno() method_id {
|
||||
return get_data().begin_parse().preload_uint(32);
|
||||
}
|
||||
|
||||
;; gets (seed, pow_complexity, amount, interval)
|
||||
(int, int, int, int) get_pow_params() method_id {
|
||||
var ds = get_data().begin_parse().skip_bits(32 + 32 + 256);
|
||||
var (seed, pow_complexity, xdata) = (ds~load_uint(128), ds~load_uint(256), ds.preload_ref());
|
||||
ds = xdata.begin_parse();
|
||||
return (seed, pow_complexity, ds~load_grams(), ds.preload_uint(32));
|
||||
}
|
||||
|
||||
int get_public_key() method_id {
|
||||
var ds = get_data().begin_parse();
|
||||
ds~load_uint(32 + 32);
|
||||
return ds.preload_uint(256);
|
||||
}
|
|
@ -46,8 +46,10 @@ $3 parse-int =: subwallet_id
|
|||
$4 parse-int =: seqno
|
||||
$5 $>cc extra-cc+! extra-currencies @ 2=: amount
|
||||
$6 "wallet-query" replace-if-null =: savefile
|
||||
subwallet_id (.) 1 ' $+ does : +subwallet
|
||||
|
||||
file-base +".addr" load-address
|
||||
file-base +subwallet +".addr" dup file-exists? { drop file-base +".addr" } ifnot
|
||||
load-address
|
||||
2dup 2constant wallet_addr
|
||||
."Source wallet address = " 2dup .addr cr 6 .Addr cr
|
||||
file-base +".pk" load-keypair nip constant wallet_pk
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue