-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fuel Mint support Part 1 - Implement HyperFuel query selection for Mint receipts #214
Changes from 6 commits
5397095
04d74ef
0f5e7f9
e328ffe
bc5d0c9
6ec4a4b
9b94dec
22b74e6
042bcfd
ea9446a
e68e56d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -136,12 +136,33 @@ let registerContractHandlers = ( | |
{{#with chain_config.network_config.hyperfuel_config as | hyperfuel_config |}} | ||
module(HyperFuelWorker.Make({ | ||
let chain = chain | ||
let contracts = contracts | ||
let endpointUrl = "{{hyperfuel_config.endpoint_url}}" | ||
let eventModLookup = | ||
contracts | ||
->Belt.Array.flatMap(contract => contract.events) | ||
->EventModLookup.fromArrayOrThrow(~chain) | ||
let contracts: array<HyperFuelWorker.contract> = [ | ||
{{#each chain_config.codegen_contracts as | contract |}} | ||
{ | ||
name: "{{contract.name.capitalized}}", | ||
addresses: [ | ||
{{#each contract.addresses as | address |}} | ||
"{{address}}"->Address.unsafeFromString, | ||
{{/each}} | ||
], | ||
events: [ | ||
{{#each contract.events as | event |}} | ||
{ | ||
name: "{{event.name.capitalized}}", | ||
logId: Types.{{contract.name.capitalized}}.{{event.name.capitalized}}.sighash, | ||
{{!-- mint: {{#if event.mint}}true{{else}}false{{/if}}, --}} | ||
eventMod: module(Types.{{contract.name.capitalized}}.{{event.name.capitalized}}), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally to pass everything via the event options and get rid of the generated eventMod (use it only for types) |
||
}, | ||
{{/each}} | ||
] | ||
}, | ||
{{/each}} | ||
] | ||
})) | ||
{{/with}} | ||
{{/if}} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,10 +3,129 @@ open Belt | |
|
||
exception EventRoutingFailed | ||
|
||
type event = { | ||
name: string, | ||
logId?: string, | ||
mint?: bool, | ||
eventMod: module(Types.Event), | ||
} | ||
|
||
type contract = { | ||
name: string, | ||
addresses: array<Address.t>, | ||
events: array<event>, | ||
} | ||
|
||
let makeGetRecieptsSelectionOrThrow = (~contracts: array<contract>) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extracted it to a factory, I'm going to write a few tests tomorrow. Ideally to do the same for HyperSync. Also, what's good about it that it'll allow to get rid of Evm specific fields from EventMod |
||
let logDataReceiptTypeSelection: array<Fuel.receiptType> = [LogData] | ||
let mintReceiptTypeSelection: array<Fuel.receiptType> = [Mint] | ||
|
||
// only transactions with status 1 (success) | ||
let txStatusSelection = [1] | ||
|
||
let mint: ref<[#None | #Wildcard | #NonWildcard]> = ref(#None) | ||
let nonWildcardRbsByContract = Js.Dict.empty() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is rbs short for? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I understand it's plural of "rb" 👍🏼 |
||
let wildcardRbs = [] | ||
|
||
let wildcardMintSelection = ( | ||
{ | ||
receiptType: mintReceiptTypeSelection, | ||
txStatus: txStatusSelection, | ||
}: HyperFuelClient.QueryTypes.receiptSelection | ||
) | ||
DZakh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let maybeWildcardLogSelection = switch wildcardRbs { | ||
| [] => None | ||
| wildcardRbs => | ||
Some( | ||
( | ||
{ | ||
receiptType: logDataReceiptTypeSelection, | ||
txStatus: txStatusSelection, | ||
rb: wildcardRbs, | ||
}: HyperFuelClient.QueryTypes.receiptSelection | ||
), | ||
) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't this always the None case? I don't see where wildcardRbs gets any values added before this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, caught this as well, while I writing tests |
||
|
||
contracts->Array.forEach(contract => { | ||
let nonWildcardRbs = [] | ||
contract.events->Array.forEach(event => { | ||
let module(Event) = event.eventMod | ||
let {isWildcard} = Event.handlerRegister->Types.HandlerTypes.Register.getEventOptions | ||
switch event { | ||
| {mint: true} => mint := (isWildcard ? #Wildcard : #NonWildcard) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like "mint" can be over written with "#Wildcard or #NonWildcard", what should happen if both appear? |
||
| {logId} => { | ||
let rb = logId->BigInt.fromStringUnsafe | ||
if isWildcard { | ||
wildcardRbs->Array.push(rb)->ignore | ||
} else { | ||
nonWildcardRbs->Array.push(rb)->ignore | ||
} | ||
} | ||
| _ => Js.Exn.raiseError(`Event ${Event.name} is not a mint or log`) | ||
} | ||
}) | ||
nonWildcardRbsByContract->Js.Dict.set(contract.name, nonWildcardRbs) | ||
}) | ||
|
||
(~contractAddressMapping, ~shouldApplyWildcards) => { | ||
let selection: array<HyperFuelClient.QueryTypes.receiptSelection> = [] | ||
|
||
//Instantiate each time to add new registered contract addresses | ||
contracts->Array.forEach(contract => { | ||
switch contractAddressMapping->ContractAddressingMap.getAddressesFromContractName( | ||
~contractName=contract.name, | ||
) { | ||
| [] => () | ||
| addresses => { | ||
if mint.contents == #NonWildcard { | ||
selection | ||
->Js.Array2.push({ | ||
rootContractId: addresses, | ||
receiptType: mintReceiptTypeSelection, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any chance you can leave some comments on the conditional logic here? It's a little difficult to understand from just the code. |
||
txStatus: txStatusSelection, | ||
}) | ||
->ignore | ||
} | ||
switch nonWildcardRbsByContract->Utils.Dict.dangerouslyGetNonOption(contract.name) { | ||
| None => () | ||
| Some(nonWildcardRbs) => | ||
selection | ||
->Js.Array2.push({ | ||
rootContractId: addresses, | ||
receiptType: logDataReceiptTypeSelection, | ||
txStatus: txStatusSelection, | ||
rb: nonWildcardRbs, | ||
}) | ||
->ignore | ||
} | ||
} | ||
} | ||
}) | ||
|
||
if shouldApplyWildcards { | ||
if mint.contents == #Wildcard { | ||
selection | ||
->Array.push(wildcardMintSelection) | ||
->ignore | ||
} | ||
switch maybeWildcardLogSelection { | ||
| None => () | ||
| Some(wildcardLogSelection) => | ||
selection | ||
->Array.push(wildcardLogSelection) | ||
->ignore | ||
} | ||
} | ||
|
||
selection | ||
} | ||
} | ||
|
||
Comment on lines
+134
to
+139
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whew 😅 this function was quite difficult to read. Maybe we can break it up a bit. I worry about logic errors creeping in when it's difficult to read end to end. |
||
module Make = ( | ||
T: { | ||
let chain: ChainMap.Chain.t | ||
let contracts: array<Config.contract> | ||
let contracts: array<contract> | ||
let endpointUrl: string | ||
let eventModLookup: EventModLookup.t | ||
}, | ||
|
@@ -90,22 +209,7 @@ module Make = ( | |
} | ||
} | ||
|
||
let wildcardLogSelection = T.contracts->Belt.Array.keepMap((contract): option< | ||
HyperFuel.contractReceiptQuery, | ||
> => { | ||
let wildcardRb = contract.events->Belt.Array.keepMap(event => { | ||
let module(Event) = event | ||
let {isWildcard} = Event.handlerRegister->Types.HandlerTypes.Register.getEventOptions | ||
isWildcard ? Some(Event.sighash->BigInt.fromStringUnsafe) : None | ||
}) | ||
switch wildcardRb { | ||
| [] => None | ||
| _ => | ||
Some({ | ||
rb: wildcardRb, | ||
}) | ||
} | ||
}) | ||
let getRecieptsSelectionOrThrow = makeGetRecieptsSelectionOrThrow(~contracts=T.contracts) | ||
|
||
let getNextPage = async ( | ||
~fromBlock, | ||
|
@@ -128,40 +232,17 @@ module Make = ( | |
) | ||
|
||
//Instantiate each time to add new registered contract addresses | ||
let contractsReceiptQuery = T.contracts->Belt.Array.keepMap((contract): option< | ||
HyperFuel.contractReceiptQuery, | ||
> => { | ||
switch contractAddressMapping->ContractAddressingMap.getAddressesFromContractName( | ||
~contractName=contract.name, | ||
) { | ||
| [] => None | ||
| addresses => | ||
Some({ | ||
addresses, | ||
rb: contract.events->Array.keepMap(eventMod => { | ||
let module(Event: Types.Event) = eventMod | ||
let {isWildcard} = Event.handlerRegister->Types.HandlerTypes.Register.getEventOptions | ||
isWildcard ? None : Some(Event.sighash->BigInt.fromStringUnsafe) | ||
}), | ||
}) | ||
} | ||
}) | ||
|
||
let contractsReceiptQuery = shouldApplyWildcards | ||
? contractsReceiptQuery->Array.concat(wildcardLogSelection) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bye bye concat |
||
: contractsReceiptQuery | ||
let recieptsSelection = getRecieptsSelectionOrThrow( | ||
~contractAddressMapping, | ||
~shouldApplyWildcards, | ||
) | ||
|
||
let startFetchingBatchTimeRef = Hrtime.makeTimer() | ||
|
||
//fetch batch | ||
let pageUnsafe = await Helpers.queryLogsPageWithBackoff( | ||
() => | ||
HyperFuel.queryLogsPage( | ||
~serverUrl=T.endpointUrl, | ||
~fromBlock, | ||
~toBlock, | ||
~contractsReceiptQuery, | ||
), | ||
HyperFuel.queryLogsPage(~serverUrl=T.endpointUrl, ~fromBlock, ~toBlock, ~recieptsSelection), | ||
logger, | ||
) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,11 +46,6 @@ type blockNumberAndHash = { | |
|
||
type logsQueryPage = hyperSyncPage<item> | ||
|
||
type contractReceiptQuery = { | ||
addresses?: array<Address.t>, | ||
rb: array<bigint>, | ||
} | ||
|
||
type missingParams = { | ||
queryName: string, | ||
missingParams: array<string>, | ||
|
@@ -89,27 +84,15 @@ let queryErrorToMsq = (e: queryError): string => { | |
type queryResponse<'a> = result<'a, queryError> | ||
|
||
module LogsQuery = { | ||
let receiptTypeSelection: array<Fuel.receiptType> = [LogData] | ||
// only transactions with status 1 (success) | ||
let txStatusSelection = [1] | ||
|
||
let makeRequestBody = ( | ||
~fromBlock, | ||
~toBlockInclusive, | ||
~contractsReceiptQuery: array<contractReceiptQuery>, | ||
~recieptsSelection, | ||
): HyperFuelClient.QueryTypes.query => { | ||
let receipts = contractsReceiptQuery->Js.Array2.map(( | ||
q | ||
): HyperFuelClient.QueryTypes.receiptSelection => { | ||
rootContractId: ?q.addresses, | ||
receiptType: receiptTypeSelection, | ||
rb: q.rb, | ||
txStatus: txStatusSelection, | ||
}) | ||
Comment on lines
-101
to
-108
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like how everything became much lighter after moving it to hyperFuelWorker |
||
{ | ||
fromBlock, | ||
toBlockExclusive: toBlockInclusive + 1, | ||
receipts, | ||
receipts: recieptsSelection, | ||
fieldSelection: { | ||
receipt: [ | ||
TxId, | ||
|
@@ -198,16 +181,13 @@ module LogsQuery = { | |
} | ||
} | ||
|
||
let queryLogsPage = async ( | ||
~serverUrl, | ||
~fromBlock, | ||
~toBlock, | ||
~contractsReceiptQuery, | ||
): queryResponse<logsQueryPage> => { | ||
let queryLogsPage = async (~serverUrl, ~fromBlock, ~toBlock, ~recieptsSelection): queryResponse< | ||
logsQueryPage, | ||
> => { | ||
let query: HyperFuelClient.QueryTypes.query = makeRequestBody( | ||
~fromBlock, | ||
~toBlockInclusive=toBlock, | ||
~contractsReceiptQuery, | ||
~recieptsSelection, | ||
) | ||
|
||
let hyperFuelClient = CachedClients.getClient(serverUrl) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally to get rid of the old contract config