urbit/pkg/arvo/app/send-txs.hoon
2019-07-16 15:59:39 -07:00

386 lines
9.2 KiB
Plaintext

::
:: there's a small state machine here that goes like this (happy path):
:: =/ wen ~
:: apex
:: -> [if =(~ wen)]
:: -> apex
:: [else]
:: -> wen=`(add now ~s10)
:: -> send-next-batch
:: [n times]
:: -> eth-send-raw-transaction
:: -> sigh-send
:: -> wait 30s in behn
:: -> wake-see
:: [n times]
:: -> wen=~
:: -> eth-get-transaction-receipt
:: -> sigh-see
:: -> apex
::
|%
++ state
$: txs=(list @ux)
see=(set @ux)
wen=(unit @da)
outstanding-send=_|
==
::
++ move (pair bone card)
++ card
$% [%hiss wire ~ mark %hiss hiss:eyre]
[%info wire ship desk nori:clay]
[%rest wire @da]
[%wait wire @da]
==
--
::
|_ [bol=bowl:gall state]
::
++ this .
++ pretty-see (turn (sort (turn ~(tap in see) mug) lth) @p)
::
++ prep
|= old=(unit *)
?: ?=([~ * * ~ @da] old)
~& [%cancelling +>+>.old]
[[ost.bol %rest /see +>+>.old]~ ..prep]
[~ ..prep]
::
:: usage:
::
:: generate txs starting from nonce 0 on fake chain at 11 gwei
:: from address; store at path
:: :send-txs [%gen %/txs/eth-txs %fake 0 11 '0x0000000']
::
:: sign txs for gasses of 2 and 11 gwei; (~ for default gwei set)
:: store at path
:: :send-txs [%sign %/txs %/txs/eth-txs %/pk/txt ~[2 0]]
::
:: read nonce range from signed transactions at path
:: :send-txs [%read %txs/txt]
::
:: send all but first 50 txs from path
:: :send-txs [%send %/txs/txt 50]
::
++ poke-noun
|= $% [%sign bout=path in=path key=path gasses=(list @ud)]
::
[%read pax=path]
::
$: %send
pax=path
how=?(%nonce %number) :: tx nonce / index in file
range=(unit $@(@ud (pair @ud @ud))) :: inclusive. end optional
==
==
^- [(list move) _this]
?- +<-
%sign
:_ this
%+ turn
?. =(~ gasses) gasses
:: default gwei set
~[3 4 6 9 11 21 31]
|= gas=@ud
%+ write-file-wain
:: add gas amount to path
=+ end=(dec (lent bout))
=- (weld (scag end bout) -)
?: =(0 gas) [(snag end bout) /txt]
:_ /txt
(cat 3 (snag end bout) (crip '-' ((d-co:co 1) gas)))
::
%- sign
:+ in key
:: modify tx gas if non-zero gwei specified
?: =(0 gas) ~
`(mul gas 1.000.000.000)
::
%read
=+ tox=.^((list cord) %cx pax)
=+ [first last]=(read-nonces tox)
~& %+ weld
"Found nonces {(scow %ud first)} through {(scow %ud last)}"
" in {(scow %ud (lent tox))} transactions."
[~ this]
::
%send
~& 'loading txs...'
=. see ~
=/ tox=(list cord) .^((list cord) %cx pax)
=. tox
?~ range tox
=* r u.range
?: ?=(%number how)
?@ r
(slag r tox)
%+ slag p.r
(scag q.r tox)
=+ [first last]=(read-nonces tox)
?: !=((lent tox) +((sub last first)))
~| 'woah, probably non-contiguous set of transactions'
!!
?@ r
(slag (sub r first) tox)
(slag (sub p.r first) (scag (sub +(q.r) first) tox))
=. txs
%+ turn tox
(cork trip tape-to-ux)
~& [(lent txs) 'loaded txs']
~& [%clearing-see ~(wyt in see)]
=. see ~
=. outstanding-send |
apex
==
::
++ get-file
|= pax=path
~| pax
.^ (list cord) %cx
(weld /(scot %p our.bol)/home/(scot %da now.bol) pax)
==
::
:: sign pre-generated transactions
++ sign
=, rpc:ethereum
|= [in=path key=path gas=(unit @ud)]
^- (list cord)
?> ?=([@ @ @ *] key)
=/ pkf (get-file t.t.t.key)
?> ?=(^ pkf)
=/ pk (rash i.pkf ;~(pfix (jest '0x') hex))
=/ txs .^((list transaction) %cx in)
=/ enumerated
=/ n 1
|- ^- (list [@ud transaction])
?~ txs
~
[[n i.txs] $(n +(n), txs t.txs)]
%+ turn enumerated
|= [n=@ud tx=transaction]
~? =(0 (mod n 100)) [%signing n]
=? gas-price.tx ?=(^ gas) u.gas
(crip '0' 'x' ((x-co:co 0) (sign-transaction:key:ethereum tx pk)))
::
++ read-nonces
|= tox=(list cord)
^- [@ud @ud]
?: =(~ tox) :: not ?~ because fucking tmi
[0 0]
:- (read-nonce (snag 0 tox))
(read-nonce (snag (dec (lent tox)) tox))
::
++ read-nonce
|= tex=cord
^- @ud
::NOTE this is profoundly stupid but should work well enough
=+ (find "82" (trip tex))
?> ?=(^ -)
(rash (rsh 3 (add u 2) (end 3 (add u 6) tex)) hex)
::
++ write-file-wain
|= [pax=path tox=(list cord)]
^- move
?> ?=([@ desk @ *] pax)
:* ost.bol
%info
(weld /write pax)
our.bol
i.t.pax
=- &+[t.t.t.pax -]~
=/ y .^(arch %cy pax)
?~ fil.y
ins+txt+!>(tox)
mut+txt+!>(tox)
==
::
++ write-file-transactions
|= [pax=path tox=(list transaction:rpc:ethereum)]
^- move
?> ?=([@ desk @ *] pax)
:* ost.bol
%info
(weld /write pax)
our.bol
i.t.pax
=- &+[t.t.t.pax -]~
=/ y .^(arch %cy pax)
?~ fil.y
ins+eth-txs+!>(tox)
mut+eth-txs+!>(tox)
==
::
++ fan-requests
|= [wir=wire nodes=(list [tag=@tas url=purl:eyre]) jon=json]
:: =- ~& [batch=((list ,[bone * wire]) (turn - |=(* [- +< +>-]:+<))) jon=jon] -
^- (list move)
%+ turn nodes
|= [tag=@tas url=purl:eyre]
^- move
:- ost.bol
:^ %hiss (weld wir ~[tag]) ~
:+ %json-rpc-response %hiss
(json-request:rpc:ethereum url jon)
::
++ batch-requests
|= [wir=wire req=(list [(unit @t) request:rpc:ethereum])]
^- (list move)
%^ fan-requests
wir
:~ => (need (de-purl:html 'http://35.226.110.143:8545'))
geth+.(p.p |)
::
=> (need (de-purl:html 'http://104.198.35.227:8545'))
parity+.(p.p |)
==
a+(turn req request-to-json:rpc:ethereum)
::
++ send-next-batch
^- [(list move) _this]
?: outstanding-send
~& 'waiting for previous send to complete'
`this
?: =(0 (lent txs))
~& 'all sent!'
[~ this(txs ~, see ~, wen ~, outstanding-send |)]
:: ~& send-next-batch=pretty-see
=/ new-count (sub 500 ~(wyt in see))
?: =(0 new-count)
~& %no-new-txs-yet
`this
:_ this(txs (slag new-count txs), outstanding-send &)
~& ['remaining txs: ' (lent txs)]
~& ['sending txs...' new-count]
%+ batch-requests /send
%+ turn (scag new-count txs)
|= tx=@ux
:- `(crip 'id-' (scot %ux (end 3 10 tx)) ~)
[%eth-send-raw-transaction tx]
::
++ sigh-json-rpc-response-send
|= [wir=wire res=response:rpc:jstd]
^- [(list move) _this]
?: ?=(%fail -.res)
~& %send-failed
`this
?> ?=(%batch -.res)
:: ~& sigh-send-a=pretty-see
=. see
%- ~(uni in see)
%- silt
^- (list @ux)
%+ murn bas.res
|= r=response:rpc:jstd
^- (unit @ux)
?: ?=(%error -.r)
?: ?| =('known transaction' (end 3 17 message.r))
=('Known transaction' (end 3 17 message.r))
=('Transaction with the same ' (end 3 26 message.r))
==
~& [%sent-a-known-transaction--skipping wir]
~
?: =('Nonce too low' message.r)
~& %nonce-too-low--skipping
~
~| :- 'transaction send failed, game over'
[code.r message.r]
!!
?> ?=(%result -.r)
:- ~
%- tape-to-ux
(sa:dejs:format res.r)
=. outstanding-send |
:: ~& sigh-send-b=pretty-see
`this
::
++ apex
^- [(list move) _this]
~& :_ ~(wyt in see)
'waiting for transaction confirms... '
?. =(~ wen) [~ this]
=. wen `(add now.bol ~s30)
:: ~& apex=[wen pretty-see]
=^ moves this send-next-batch
:: timer got un-set, meaning we're done here
?~ wen [moves this]
[[[ost.bol %wait /see (need wen)] moves] this]
::
++ wake-see
|= [wir=wire ~]
^- [(list move) _this]
=. wen ~
:: ~& wake-see=[wen pretty-see]
?: =(~ see)
apex
:_ this
%+ batch-requests /see
%+ turn ~(tap in see)
|= txh=@ux
:- `(crip 'see-0x' ((x-co:co 64) txh))
[%eth-get-transaction-receipt txh]
::
++ sigh-json-rpc-response-see
|= [wir=wire res=response:rpc:jstd]
^- [(list move) _this]
?: ?| ?=(%error -.res)
?=(%fail -.res)
==
~& [%bad-rpc-response--kicking res]
apex
:: `this
?> ?=(%batch -.res)
?: =(~ see)
apex
?: =(0 (lent bas.res))
::TODO node lost our txs?
~& [%txs-lost-tmp wir '!!']
apex
:: ~& sigh-see-a=pretty-see
=. see
%- ~(dif in see)
%- silt
^- (list @ux)
%+ murn bas.res
|= r=response:rpc:jstd
^- (unit @ux)
?< ?=(%batch -.r)
?< ?=(%fail -.r)
~| [id.r res]
=+ txh=(tape-to-ux (trip (rsh 3 4 id.r)))
:: ~& see-tx=[(@p (mug txh)) `@ux`txh]
=* done `txh
=* wait ~
?: ?=(%error -.r)
~& :- 'receipt fetch error'
[code.r message.r]
wait
?~ res.r wait
?> ?=(%o -.res.r)
=/ status
%- tape-to-ux
%- sa:dejs:format
(~(got by p.res.r) 'status')
?: =(1 status)
done
~& [%see-bad-status status]
wait
:: ~& sigh-see-b=pretty-see
apex
::
++ sigh-tang
|= [wir=wire err=tang]
~& [%sigh-tang wir]
~& (slog err)
?: =(~ wen) [~ this]
=. wen `(add now.bol ~s30)
[[ost.bol %wait /see (need wen)]~ this]
::
++ tape-to-ux
|= t=tape
(scan t zero-ux)
::
++ zero-ux
;~(pfix (jest '0x') hex)
--