mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-19 04:41:37 +03:00
Merge pull request #5671 from urbit/jon/l2-csv
L2 transaction gas costs csv thread
This commit is contained in:
commit
8d2ddfd467
33
pkg/arvo/ted/eth/get-tx-receipts.hoon
Normal file
33
pkg/arvo/ted/eth/get-tx-receipts.hoon
Normal file
@ -0,0 +1,33 @@
|
||||
:: eth/get-tx-receipts
|
||||
::
|
||||
:: asks an ethereum node for transaction receipts from a list of transaction
|
||||
:: hashes. returns a (list [@t json]), where @t is the transaction hash in
|
||||
:: hex written as a cord, and json is the receipt
|
||||
::
|
||||
/+ ethereum, ethio, *strandio
|
||||
=, jael
|
||||
::
|
||||
|= args=vase
|
||||
=+ !<([url=@t tx-hashes=(list @ux)] args)
|
||||
=/ m (strand ,vase)
|
||||
=| out=(list [@t json])
|
||||
|^
|
||||
^- form:m
|
||||
=* loop $
|
||||
?: =(~ tx-hashes) (pure:m !>(out))
|
||||
;< res=(list [@t json]) bind:m
|
||||
(request-receipts url (scag 100 tx-hashes))
|
||||
%_ loop
|
||||
out (welp out res)
|
||||
tx-hashes (slag 100 tx-hashes)
|
||||
==
|
||||
::
|
||||
++ request-receipts
|
||||
|= [url=@t tx-hashes=(list @ux)]
|
||||
%+ request-batch-rpc-strict:ethio url
|
||||
%+ turn tx-hashes
|
||||
|= txh=@ux
|
||||
^- [(unit @t) request:rpc:ethereum]
|
||||
:- `(crip '0' 'x' ((x-co:co 64) txh))
|
||||
[%eth-get-transaction-receipt txh]
|
||||
--
|
390
pkg/arvo/ted/naive-csv.hoon
Normal file
390
pkg/arvo/ted/naive-csv.hoon
Normal file
@ -0,0 +1,390 @@
|
||||
:: naive-csv: produces csv file containing L2 transaction data
|
||||
::
|
||||
:: takes in the network to use and the ethereum node url to grab data from.
|
||||
:: it starts with the azimuth snapshot and scries the logs from %azimuth.
|
||||
:: it then produces a csv file containing the following data on L2
|
||||
:: transactions:
|
||||
::
|
||||
:: - block number
|
||||
:: - timestamp
|
||||
:: - roller address
|
||||
:: - roll hash
|
||||
:: - tx hash
|
||||
:: - sending ship
|
||||
:: - sending proxy
|
||||
:: - nonce
|
||||
:: - gas price
|
||||
:: - length of input data
|
||||
:: - success or failure
|
||||
:: - function name
|
||||
:: - spawning ship (^sein:title)
|
||||
::
|
||||
:: A lot of the data-scrounging here is stuff that %roller already keeps track
|
||||
:: of. We could just scry it from there, but then this thread needs to be run
|
||||
:: on the roller ship. So we rebuild the list of historical transactions
|
||||
:: ourselves so that this can run from any ship.
|
||||
::
|
||||
/- dice,
|
||||
spider
|
||||
::
|
||||
/+ dice,
|
||||
ethereum,
|
||||
ethio,
|
||||
naive,
|
||||
naive-tx=naive-transactions,
|
||||
*strandio
|
||||
:: starting snapshot. this may not be the right starting point once we have
|
||||
:: clay tombstoning and the snapshot may be updated
|
||||
::
|
||||
/* snap %azimuth-snapshot /app/azimuth/version-0/azimuth-snapshot
|
||||
::
|
||||
=, strand=strand:spider
|
||||
=, jael
|
||||
::
|
||||
^- thread:spider
|
||||
=< process-logs
|
||||
=>
|
||||
|%
|
||||
:: imported logs is cast as $events
|
||||
+$ events (list event-log:rpc:ethereum)
|
||||
+$ address address:naive :: @ux
|
||||
+$ keccak @ux :: used for transaction and roll hashes
|
||||
+$ blocknum number:block :: @udblocknumber
|
||||
+$ net net:dice :: ?(%mainnet %ropsten %local %default)
|
||||
+$ roll-dat :: all data required for each roll
|
||||
[[gas=@ud sender=address] =effects:naive]
|
||||
+$ block-dat :: all data required for each block
|
||||
[timestamp=@da rolls=(map keccak roll-dat)]
|
||||
+$ block-map (map blocknum block-dat)
|
||||
+$ rolls-map (map blocknum (map keccak effects:naive))
|
||||
::
|
||||
+$ action
|
||||
$? %transfer-point
|
||||
%spawn
|
||||
%configure-keys
|
||||
%escape
|
||||
%cancel-escape
|
||||
%adopt
|
||||
%reject
|
||||
%detach
|
||||
%set-management-proxy
|
||||
%set-spawn-proxy
|
||||
%set-transfer-proxy
|
||||
==
|
||||
::
|
||||
+$ tx-data
|
||||
$: =blocknum
|
||||
timestamp=@da
|
||||
roller=address
|
||||
roll-hash=keccak
|
||||
tx-hash=keccak
|
||||
sender=ship
|
||||
proxy=proxy:naive
|
||||
nonce=nonce:naive
|
||||
gas=@ud
|
||||
length=@ux
|
||||
suc=?
|
||||
=action
|
||||
parent=ship
|
||||
==
|
||||
--
|
||||
::
|
||||
|%
|
||||
:: +process-logs is the main process. it grabs the azimuth snapshop, runs
|
||||
:: +naive on the logs, grabs the timestamps and gas costs for each roll,
|
||||
:: then flattens them into a list of $tx-data and saves them to disk.
|
||||
::
|
||||
++ process-logs
|
||||
|= arg=vase
|
||||
=+ !<([~ =net node-url=@t] arg)
|
||||
=/ pax=path /naive-exports/csv :: data will be saved here
|
||||
=/ m (strand ,vase)
|
||||
^- form:m
|
||||
;< =events bind:m (scry events /gx/azimuth/logs/noun)
|
||||
=/ [naive-contract=address chain-id=@]
|
||||
[naive chain-id]:(get-network:dice net)
|
||||
=/ snap=snap-state:dice snap
|
||||
::
|
||||
;< ~ bind:m
|
||||
%- flog-text %+ weld "naive-csv: processing {<net>} ethereum logs "
|
||||
"with {<(lent events)>} events"
|
||||
=/ =rolls-map
|
||||
(compute-effects nas.snap events net naive-contract chain-id)
|
||||
;< ~ bind:m (flog-text "naive-csv: getting timestamps")
|
||||
;< tim=thread-result bind:m
|
||||
%+ await-thread %eth-get-timestamps
|
||||
!>([node-url ~(tap in ~(key by rolls-map))])
|
||||
=/ timestamps %- ~(gas by *(map blocknum @da))
|
||||
?- tim
|
||||
[%.y *] ;;((list [@ud @da]) q.p.tim)
|
||||
[%.n *]
|
||||
=> (mean 'naive-csv: %eth-get-timestamps failed' p.tim)
|
||||
!!
|
||||
==
|
||||
;< ~ bind:m (flog-text "naive-csv: got timestamps")
|
||||
;< ~ bind:m (flog-text "naive-csv: getting tx receipts")
|
||||
;< gaz=thread-result bind:m
|
||||
%+ await-thread %eth-get-tx-receipts
|
||||
!>([node-url (get-roll-hashes rolls-map)])
|
||||
=/ gas-sender %- ~(gas by *(map keccak [gas=@ud sender=address]))
|
||||
?- gaz
|
||||
[%.y *] (parse-gas-sender ;;((list [@t json]) q.p.gaz))
|
||||
[%.n *]
|
||||
=> (mean 'naive-csv: %eth-tx-receipts failed' p.gaz)
|
||||
!!
|
||||
==
|
||||
;< ~ bind:m (flog-text "naive-csv: got tx receipts")
|
||||
=/ csv=(list cord)
|
||||
(make-csv (flatten (collate-roll-data rolls-map timestamps gas-sender)))
|
||||
;< ~ bind:m (export-csv csv pax)
|
||||
;< ~ bind:m (flog-text :(weld "naive-csv: csv saved to %" (spud pax) "/"))
|
||||
::
|
||||
(pure:m !>(~))
|
||||
:: +collate-roll-data throws naive:effects, timestamps, and gas costs into
|
||||
:: one $block-map
|
||||
::
|
||||
++ collate-roll-data
|
||||
|= $: =rolls-map
|
||||
timestamps=(map blocknum @da)
|
||||
roll-receipts=(map keccak [gas=@ud sender=address])
|
||||
==
|
||||
=/ blocknums=(list blocknum) ~(tap in ~(key by rolls-map))
|
||||
=| =block-map
|
||||
^+ block-map
|
||||
|-
|
||||
?~ blocknums block-map
|
||||
=/ =blocknum i.blocknums
|
||||
=/ rolls=(map keccak [[gas=@ud sender=address] =effects:naive])
|
||||
%- ~(gas by *(map keccak [[gas=@ud sender=address] =effects:naive]))
|
||||
%+ turn ~(tap in ~(key by (~(got by rolls-map) blocknum)))
|
||||
|= txh=keccak
|
||||
:+ txh
|
||||
(~(got by roll-receipts) txh)
|
||||
(~(got by (~(got by rolls-map) blocknum)) txh)
|
||||
%= $
|
||||
blocknums t.blocknums
|
||||
block-map %+ ~(put by block-map)
|
||||
blocknum
|
||||
[(~(got by timestamps) blocknum) rolls]
|
||||
==
|
||||
:: +flatten takes a $block-map and creates a $tx-data for every transaction
|
||||
:: in every roll, returned as a (list tx-data)
|
||||
::
|
||||
++ flatten
|
||||
|= =block-map
|
||||
=/ blocks=(list [blocknum block-dat]) ~(tap by block-map)
|
||||
=| tx-list=(list tx-data)
|
||||
^+ tx-list
|
||||
:: recurse through the list of blocks, getting the rolls submitted in that
|
||||
:: block, their timestamp, and the gas price of that roll
|
||||
::
|
||||
|-
|
||||
=* block-loop $
|
||||
?~ blocks tx-list
|
||||
=/ block=[=blocknum =block-dat] i.blocks
|
||||
=/ roll-list=(list [=keccak =roll-dat]) ~(tap by rolls.block-dat.block)
|
||||
=| block-tx-list=(list tx-data)
|
||||
:: recurse through each roll, getting the transaction data from the effects
|
||||
::
|
||||
|-
|
||||
=* roll-loop $
|
||||
?~ roll-list
|
||||
%= block-loop
|
||||
blocks t.blocks
|
||||
tx-list (welp tx-list block-tx-list)
|
||||
==
|
||||
=/ roll=[=keccak =roll-dat] i.roll-list
|
||||
:: recurse through the list of effects, building up transaction data as we
|
||||
:: go. there's a choice here to use the effects, or the submitted
|
||||
:: raw-tx. the effects include whether or not a transaction failed,
|
||||
:: which is important data not a part of the submitted raw-tx. we
|
||||
:: could determine this ourselves, but we build the effects anyways when
|
||||
:: computing the state transitions, so we may as well use them.
|
||||
::
|
||||
:: an individual transaction results in up to 3 diffs: a %nonce, a %tx, and
|
||||
:: a %point. they always appear in this order. successful transactions
|
||||
:: always have all 3, while failed transactions only have %nonce and %tx.
|
||||
:: note that the nonce listed is always the expected nonce - we can't know
|
||||
:: what nonce was actually submitted without the private key of the signer.
|
||||
::
|
||||
=| roll-tx-list=(list tx-data)
|
||||
=| =tx-data
|
||||
=| nonce-and-tx=[_| _|]
|
||||
|-
|
||||
=* effect-loop $
|
||||
:: if we are processing a new transaction, initialize the parts of tx-data
|
||||
:: that are identical for every transaction in the roll
|
||||
=? tx-data =([| |] nonce-and-tx)
|
||||
:* blocknum.block timestamp.block-dat.block sender.roll-dat.roll
|
||||
keccak.roll *keccak *ship *proxy:naive *nonce:naive
|
||||
gas.roll-dat.roll *@ | *action *ship
|
||||
==
|
||||
:: if we've gotten both the %nonce and %tx diff from a transaction, add the
|
||||
:: tx-data to the list of tx for the roll
|
||||
::
|
||||
?: =([& &] nonce-and-tx)
|
||||
%= effect-loop
|
||||
nonce-and-tx [| |]
|
||||
roll-tx-list (snoc roll-tx-list tx-data)
|
||||
==
|
||||
:: if we've finished looping through the effects, add the tx list from the
|
||||
:: roll to the list of tx for the block
|
||||
::
|
||||
?~ effects.roll-dat.roll
|
||||
%= roll-loop
|
||||
roll-list t.roll-list
|
||||
block-tx-list (welp block-tx-list roll-tx-list)
|
||||
==
|
||||
::
|
||||
=/ =diff:naive i.effects.roll-dat.roll
|
||||
:: we ignore %operator, %dns, %point diffs
|
||||
::
|
||||
?+ diff
|
||||
$(effects.roll-dat.roll t.effects.roll-dat.roll)
|
||||
:: %nonce is always the first diff from a given transaction.
|
||||
::
|
||||
[%nonce *]
|
||||
%= effect-loop
|
||||
-.nonce-and-tx &
|
||||
sender.tx-data ship.diff
|
||||
nonce.tx-data nonce.diff
|
||||
proxy.tx-data proxy.diff
|
||||
parent.tx-data (^sein:title ship.diff)
|
||||
effects.roll-dat.roll t.effects.roll-dat.roll
|
||||
==
|
||||
:: %tx is always the second diff from a given transaction.
|
||||
::
|
||||
[%tx *]
|
||||
%= effect-loop
|
||||
+.nonce-and-tx &
|
||||
effects.roll-dat.roll t.effects.roll-dat.roll
|
||||
action.tx-data +<.tx.raw-tx.diff
|
||||
suc.tx-data ?~ err.diff & |
|
||||
length.tx-data `@`-.raw.raw-tx.diff
|
||||
tx-hash.tx-data (hash-raw-tx:naive-tx raw-tx.diff)
|
||||
==
|
||||
==
|
||||
::
|
||||
++ parse-gas-sender
|
||||
|= res=(list [@t json])
|
||||
^- (list [=keccak [gas=@ud sender=address]])
|
||||
%+ turn res
|
||||
|= [id=@t =json]
|
||||
^- [=keccak [gas=@ud sender=address]]
|
||||
:- (hex-to-num:ethereum id)
|
||||
:- %- parse-hex-result:rpc:ethereum
|
||||
~| json
|
||||
?> ?=(%o -.json)
|
||||
(~(got by p.json) 'effectiveGasPrice') :: gas used in wei
|
||||
%- parse-hex-result:rpc:ethereum
|
||||
~| json
|
||||
?> ?=(%o -.json)
|
||||
(~(got by p.json) 'from')
|
||||
:: +get-roll-hashes makes a list of hashes of all transactions from $rolls-map
|
||||
::
|
||||
++ get-roll-hashes
|
||||
|= =rolls-map ^- (list keccak)
|
||||
%- zing
|
||||
%+ turn ~(val by rolls-map)
|
||||
|= a=(map keccak effects:naive)
|
||||
~(tap in ~(key by a))
|
||||
:: +compute-effects calls +naive to compute the state transitions for all
|
||||
:: logs, but it returns a map that only has the effects for L2 transactions,
|
||||
:: leaving out L1 transactions. we need to compute all of them in order to
|
||||
:: determine whether the transactions were valid.
|
||||
::
|
||||
++ compute-effects
|
||||
|= $: nas=^state:naive
|
||||
=events
|
||||
=net
|
||||
naive-contract=address
|
||||
chain-id=@ud
|
||||
==
|
||||
=| out=rolls-map
|
||||
^+ out
|
||||
::
|
||||
|-
|
||||
?~ events out
|
||||
=/ log=event-log:rpc:ethereum i.events
|
||||
?~ mined.log
|
||||
~& >> 'naive-csv: empty log'
|
||||
$(events t.events)
|
||||
=/ =blocknum block-number.u.mined.log
|
||||
=/ =^input:naive
|
||||
:- blocknum
|
||||
?. =(naive-contract address.log)
|
||||
:- %log
|
||||
[address.log (data-to-hex:dice data.log) topics.log]
|
||||
?~ input.u.mined.log
|
||||
~& >> 'naive-csv: empty L2 transaction'
|
||||
[%bat *@]
|
||||
[%bat u.input.u.mined.log]
|
||||
=^ =effects:naive nas
|
||||
(%*(. naive lac |) verifier:naive-tx chain-id nas input)
|
||||
%= $
|
||||
events t.events
|
||||
out ?. =(%bat +<.input)
|
||||
out :: skip L1 logs
|
||||
=/ cur (~(get by out) blocknum)
|
||||
?~ cur
|
||||
%+ ~(put by out) blocknum
|
||||
(my [[transaction-hash.u.mined.log effects]~])
|
||||
%+ ~(put by out) blocknum
|
||||
(~(put by u.cur) transaction-hash.u.mined.log effects)
|
||||
==
|
||||
:: +export-csv writes a (list cord) as csv to disk at .pax
|
||||
::
|
||||
++ export-csv
|
||||
|= [in=(list cord) pax=path]
|
||||
=/ m (strand ,~)
|
||||
^- form:m
|
||||
;< =bowl:spider bind:m get-bowl
|
||||
=- (send-raw-card %pass / %arvo %c %info -)
|
||||
%+ foal:space:userlib
|
||||
;: weld
|
||||
/(scot %p our.bowl)/base/(scot %da now.bowl)
|
||||
pax
|
||||
/(scot %da now.bowl)/txt
|
||||
==
|
||||
[%txt !>(in)]
|
||||
:: +make-csv takes in a (list tx-data) and makes it into a (list cord) to be
|
||||
:: saved as a csv file
|
||||
::
|
||||
++ make-csv
|
||||
|= in=(list tx-data)
|
||||
^- (list cord)
|
||||
:- %- crip
|
||||
;: weld
|
||||
"block number,"
|
||||
"timestamp,"
|
||||
"roller address,"
|
||||
"roll hash,"
|
||||
"tx hash,"
|
||||
"sending ship,"
|
||||
"sending proxy,"
|
||||
"nonce,"
|
||||
"gas price,"
|
||||
"length of input data,"
|
||||
"success or failure,"
|
||||
"function name,"
|
||||
"parent"
|
||||
==
|
||||
%+ turn in
|
||||
|= =tx-data
|
||||
%- crip
|
||||
;: weld
|
||||
(scow %ud blocknum.tx-data) ","
|
||||
(scow %da timestamp.tx-data) ","
|
||||
(scow %ux roller.tx-data) ","
|
||||
(scow %ux roll-hash.tx-data) ","
|
||||
(scow %ux tx-hash.tx-data) ","
|
||||
(scow %p sender.tx-data) ","
|
||||
(scow %tas proxy.tx-data) ","
|
||||
(scow %ud nonce.tx-data) ","
|
||||
(scow %ud gas.tx-data) ","
|
||||
(scow %ux length.tx-data) ","
|
||||
(scow %f suc.tx-data) ","
|
||||
(scow %tas action.tx-data) ","
|
||||
(scow %p parent.tx-data)
|
||||
==
|
||||
--
|
Loading…
Reference in New Issue
Block a user