diff --git a/README.md b/README.md index 4c5fdf9..4e49ab4 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,20 @@ -# Transaction Village +# [Transaction Village](https://github.com/mlabs-haskell/tx-village) ## Packages -- [ledger-sim](./ledger-sim/) - Haskell based Ledger simulator -- [tx-bakery](./tx-bakery) - Transaction Bakery - Rust based transaction builder +- [tx-bakery](https://github.com/mlabs-haskell/tx-village/tree/main/tx-indexer) - Transaction Bakery - Rust based transaction builder library -- [tx-indexer](./tx-indexer/) - Transaction Indexer - Rust based chain follower +- [tx-indexer](https://github.com/mlabs-haskell/tx-village/tree/main/tx-indexer) - Transaction Indexer - Rust based chain follower and indexer -## Documents - -- [Contributing guideline](/CONTRIBUTING.md) -- [License](/LICENSE) - - ## API References - [tx-bakery](./artifacts/tx-bakery/tx_bakery/index.html) - [tx-bakery-ogmios](./artifacts/tx-bakery-ogmios/tx_bakery_ogmios/index.html) - [tx-bakery-plutip](./artifacts/tx-bakery-plutip/tx_bakery_plutip/index.html) +- [tx-indexer](./artifacts/tx-indexer/tx_indexer/index.html) + +## Documents + +- [Contributing guideline](https://github.com/mlabs-haskell/tx-village/blob/main/CONTRIBUTING.md) +- [License](https://github.com/mlabs-haskell/tx-village/blob/main/LICENSE) diff --git a/artifacts/tx-indexer/.lock b/artifacts/tx-indexer/.lock new file mode 100644 index 0000000..e69de29 diff --git a/artifacts/tx-indexer/crates.js b/artifacts/tx-indexer/crates.js new file mode 100644 index 0000000..08d80c1 --- /dev/null +++ b/artifacts/tx-indexer/crates.js @@ -0,0 +1 @@ +window.ALL_CRATES = ["tx_indexer"]; \ No newline at end of file diff --git a/artifacts/tx-indexer/help.html b/artifacts/tx-indexer/help.html new file mode 100644 index 0000000..6347211 --- /dev/null +++ b/artifacts/tx-indexer/help.html @@ -0,0 +1,2 @@ +
U::from(self)
.","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","","Calls U::from(self)
.","","","","","","","","","","","","","","Typed network magic restricted to specific networks fully …","","Simple description on how to connect to a local or remote …","","","Hostname and port number for TCP connection to remote node","","Path to Unix node.socket","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","","","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","","","","Retry policy - how much to retry for each event callback …","Minimum depth a block has to be from the tip for it to be …","Slot number and hash as hex string (optional). If not …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Address","AssetQuantity","","","ChainPointer","Credential","CurrencySymbol","","DatumHash","Ed25519PubKeyHash","","OutputDatum","","PlutusData","","ScriptHash","Slot","StakingCredential","TokenName","TransactionHash","TransactionInput","TransactionOutput","","","TxInInfo","Value","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","","","Returns the argument unchanged.","","Returns the argument unchanged.","Returns the argument unchanged.","","Returns the argument unchanged.","","Returns the argument unchanged.","","","Returns the argument unchanged.","","Returns the argument unchanged.","","","Returns the argument unchanged.","","Returns the argument unchanged.","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","","Obtain the sync status of the DB","","Calls U::from(self)
.","","Save a new entity to the database.","","","","","","","","","","","Indicate that the event handler should call given error …","Specify what the indexer event handler should do for …","Trait that can be implemented for custom error types. …","Indicate that the event handler should exit with error.","Indicate the callback operation should be retried. Also …","Indicate that the error should be ignored, go to next …","","","Returns the argument unchanged.","","Calls U::from(self)
.","","","","","","","","","","Interesting transaction components to look for when …","","","","Returns the argument unchanged.","Calls U::from(self)
.","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","","Calls U::from(self)
.","","","","","","","","","","","Chain events that the indexer is configured to produce.","Indication of when an event happened in the context of the …","Rollback event occurred","Chain syncronisation progressed","A filtered transaction was confirmed","Details on an transaction event (excluding unnecessary …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","","Calls U::from(self)
.","Calls U::from(self)
.","Calls U::from(self)
.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Influence retrying behavior. i.e How many times and how …","","","","","","","","","","Returns the argument unchanged.","Calls U::from(self)
.","","","","","","","","","","","","","A progress tracker holds information about the chain info …","","","","","","","","Returns the argument unchanged.","","Calls U::from(self)
.","","","","","","","","","","","","","",""],"i":[0,0,2,2,0,0,0,0,2,2,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,0,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,17,16,0,0,0,0,16,16,21,0,21,17,16,17,18,1,21,16,17,18,1,21,16,17,18,16,17,18,16,17,18,0,18,18,18,18,1,16,16,17,18,18,1,21,16,17,18,16,16,1,1,21,16,17,18,1,1,1,1,1,1,17,17,16,17,18,1,21,16,17,18,16,18,1,21,16,17,18,1,21,16,17,18,1,21,16,17,18,1,21,16,17,18,1,21,16,17,18,1,21,16,17,18,1,21,16,17,18,1,21,16,17,18,99,99,0,0,0,0,0,0,61,62,0,0,0,0,0,0,61,0,0,0,61,0,0,0,0,0,0,0,62,62,0,0,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,44,45,46,47,48,50,51,52,53,61,36,37,38,39,40,41,42,62,43,44,45,46,47,48,49,50,51,52,53,61,36,37,38,39,40,41,42,62,43,44,45,46,47,48,49,50,51,52,53,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,42,42,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,36,36,36,37,37,37,38,38,38,39,39,39,40,40,40,41,41,41,42,42,42,43,43,43,44,44,44,45,45,45,46,46,46,47,47,47,48,48,48,49,49,49,50,50,50,51,51,51,52,52,52,53,53,53,61,61,36,37,38,39,40,41,42,62,62,43,44,45,46,47,48,49,50,51,52,53,61,61,36,36,37,37,38,38,39,39,40,40,41,41,42,42,62,62,62,62,43,44,44,45,46,47,48,49,50,51,52,53,61,36,37,38,39,40,41,42,62,43,44,45,46,47,48,49,50,51,52,53,42,36,37,38,39,40,41,42,43,49,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,61,62,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,61,36,37,38,39,40,41,42,62,43,44,45,46,47,48,49,50,51,52,53,61,62,61,36,37,38,39,40,41,42,62,43,43,44,45,45,46,46,47,47,48,48,49,49,50,50,51,51,52,52,53,53,61,36,37,38,39,40,41,42,62,43,44,45,46,47,48,49,50,51,52,53,61,36,37,38,39,40,41,42,62,43,44,45,46,47,48,49,50,51,52,53,61,36,37,38,39,40,41,42,62,43,44,45,46,47,48,49,50,51,52,53,61,36,37,38,39,40,41,42,62,43,44,45,46,47,48,49,50,51,52,53,61,36,37,38,39,40,41,42,62,43,44,45,46,47,48,49,50,51,52,53,61,36,37,38,39,40,41,42,62,43,44,45,46,47,48,49,50,51,52,53,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,61,36,37,38,39,40,41,42,62,43,44,45,46,47,48,49,50,51,52,53,0,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,87,0,0,87,87,87,87,87,87,86,87,87,87,87,87,87,87,87,87,87,0,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,0,0,0,5,0,89,0,89,89,89,89,5,89,89,89,89,89,89,89,89,89,89,89,0,0,91,91,91,0,94,91,95,94,94,94,91,95,94,91,95,94,91,95,94,91,95,94,91,95,94,94,94,95,95,95,95,94,91,95,94,91,95,95,95,94,91,95,95,95,0,95,95,94,94,91,95,94,91,95,94,91,95,94,91,95,94,91,95,94,91,95,94,91,95,94,91,95,94,91,95,94,91,95,100,101,100,101,101,102,102,0,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,0,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97],"f":"``{ce{}{}}0`````{cc{}}`1`{{{b{c}}}{{h{df}}}j}``2{c{{l{e}}}{}{}}0{c{{l{en}}}{}{}}0{c{{l{eA`}}}{}{}}0{cAb{}}6`{{cAd}Af{}}77{AhAh}{{ce}Af{}{}}{{AhAj}Al}9{An{{l{Ahc}}}{}};;;8877665;````````````444;;;;;;;;;;{B`B`}{BbBb}{BdBd}555`{{BdBd}Bf}{{ce}Bf{}{}}00`{{B`Aj}{{l{AfBh}}}}{{B`Aj}Al}{{BbAj}Al}{{BdAj}Al}0{cc{}}0000{An{{l{c}}}{}}{An{{l{B`c}}}{}}`{ce{}{}}0000`{{cBjBb{Cb{{C`{BlBn}}}}CdCfCh}{{b{c}}}j}````{Bb{{l{CjCl}}}}{BbCn}33333333{cBn{}}0{c{{l{e}}}{}{}}000000000{c{{l{en}}}{}{}}000000000{c{{l{eA`}}}{}{}}000000000{cAb{}}000088888``{{D`Cn{Cb{{C`{BlBn}}}}Cd}Db}{{D`Cn{Cb{{C`{BlBn}}}}Cd}Dd}````````````````````````````{{cAd}Af{}}00000000000000000{{}Df}00000000<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<{DhDh}{DjDj}{DlDl}{DnDn}{E`E`}{EbEb}{EdEd}{EfEf}{EhEh}{EjEj}{ElEl}{EnEn}{F`F`}{FbFb}{FdFd}{FfFf}{FhFh}{FjFj}{{ce}Af{}{}}00000000000000000{{EdEd}Fl}{{ce}Fl{}{}}{{}{{l{Dh{G`{Fn}}}}}}{{}{{l{Dj{G`{Fn}}}}}}{{}{{l{Dl{G`{Fn}}}}}}{{}{{l{Dn{G`{Fn}}}}}}{{}{{l{E`{G`{Fn}}}}}}{{}{{l{Eb{G`{Fn}}}}}}{{}{{l{Ed{G`{Fn}}}}}}{{}{{l{Ef{G`{Fn}}}}}}{Gb{{l{Eh{G`{Fn}}}}}}{Gb{{l{Ej{G`{Fn}}}}}}{Gb{{l{El{G`{Fn}}}}}}{Gb{{l{En{G`{Fn}}}}}}{Gb{{l{F`{G`{Fn}}}}}}{{}{{l{Fb{G`{Fn}}}}}}{Gb{{l{Fd{G`{Fn}}}}}}{Gb{{l{Ff{G`{Fn}}}}}}{Gb{{l{Fh{G`{Fn}}}}}}{Gb{{l{Fj{G`{Fn}}}}}}{Dh{{l{GdGf}}}}{Dj{{l{GdGf}}}}{Dl{{l{GdGf}}}}{Dn{{l{GdGf}}}}{E`{{l{GdGf}}}}{Eb{{l{GdGf}}}}{Ed{{l{GdGf}}}}{Ef{{l{GdGf}}}}{{EhGh}{{l{GdGf}}}}{{EjGh}{{l{GdGf}}}}{{ElGh}{{l{GdGf}}}}{{EnGh}{{l{GdGf}}}}{{F`Gh}{{l{GdGf}}}}{Fb{{l{GdGf}}}}{{FdGh}{{l{GdGf}}}}{{FfGh}{{l{GdGf}}}}{{FhGh}{{l{GdGf}}}}{{FjGh}{{l{GdGf}}}}{{DhDh}Bf}{{DjDj}Bf}{{DlDl}Bf}{{DnDn}Bf}{{E`E`}Bf}{{EbEb}Bf}{{EdEd}Bf}{{EfEf}Bf}{{EhEh}Bf}{{EjEj}Bf}{{ElEl}Bf}{{EnEn}Bf}{{F`F`}Bf}{{FbFb}Bf}{{FdFd}Bf}{{FfFf}Bf}{{FhFh}Bf}{{FjFj}Bf}{{ce}Bf{}{}}00000000000000000000000000000000000000000000000000000{{GjAj}Al}0{{DhAj}Al}{{DjAj}Al}{{DlAj}Al}{{DnAj}Al}{{E`Aj}Al}{{EbAj}Al}{{EdAj}Al}{{GlAj}Al}0{{EfAj}Al}{{EhAj}Al}{{EjAj}Al}{{ElAj}Al}{{EnAj}Al}{{F`Aj}Al}{{FbAj}Al}{{FdAj}Al}{{FfAj}Al}{{FhAj}Al}{{FjAj}Al}{cc{}}{GlGj}{GnDh}2{H`Dj}33{HbDl}4{HdDn}5{HfE`}{HhEb}7{BlEd}8{A`Gl}{nGl}:{HjGl};{HlEh}<<<<<<<<<<{ce{}{}}0000000000000000000{{EdEd}{{Cb{Fl}}}}{DhCb}{DjCb}{DlCb}{DnCb}{E`Cb}{EbCb}{EdCb}{EfCb}{FbCb}{DhCd}{DjCd}{DlCd}{DnCd}{E`Cd}{EbCd}{EdCd}{EfCd}{EhCd}{EjCd}{ElCd}{EnCd}{F`Cd}{FbCd}{FdCd}{FfCd}{FhCd}{FjCd}{Gj{{Cb{Fn}}}}{Gl{{Cb{Fn}}}}{ce{}{}}0000000000000000000000000000000000000{cBn{}}0{c{{l{e}}}{}{}}000000000{Hn{{l{Efc}}}{}}11{I`{{l{Ejc}}}{}}2{Ib{{l{Elc}}}{}}{Id{{l{Enc}}}{}}4{{{C`{GnH`If}}}{{l{F`c}}}{}}55{Ih{{l{Fbc}}}{}}{Ij{{l{Fdc}}}{}}77{Il{{l{Ffc}}}{}}{In{{l{Fhc}}}{}}99{J`{{l{Fjc}}}{}}::::::::::::::::::::{c{{l{en}}}{}{}}000000000000000000000000000000000000000{c{{l{eA`}}}{}{}}000000000000000000000000000000000000000{cAb{}}0000000000000000000{{}Df}00000000000000000{ce{}{}}0000000000000000000`{{cAd}Af{}}``11{JbJb}{{ce}Af{}{}}{{JbJb}Bf}{{ce}Bf{}{}}00{{JbAj}Al}{cc{}}{c{{Jd{Jb}}}Jf}{Jh{{l{{Cb{Jb}}Jj}}}}{{Jh{Cb{Bl}}{Cb{Bn}}}{{l{{Cb{{C`{BlBn}}}}Cl}}}}:{{BlBn}{{l{JbCl}}}}{{JbJh}{{l{AfJj}}}}<<{c{{l{e}}}{}{}}0{c{{l{en}}}{}{}}0{c{{l{eA`}}}{}{}}0{cAb{}}{ce{}{}}``````00:{Jl{{Jn{Jl}}}}1155443321`11`;11{CfK`}66554432```````22{{KbAj}{{l{AfBh}}}}={{{j{}{{Kd{c}}}}Kf}{{`{{Kj{}{{Kh{{l{Afc}}}}}}}}}{FnJl}}44{cBn{}}99887765``````{{cAd}Af{}}00``666666{KlKl}{KfKf}{KnKn}{{ce}Af{}{}}00{{KlKl}Bf}{{KfKf}Bf}{{KnKn}Bf}{{ce}Bf{}{}}00000`{{KlAj}Al}{{KfAj}Al}{{KnAj}Al}{cc{}}00``{ce{}{}}00``{{L`{Cb{Lb}}}{{l{{Cb{Kf}}`}}}}```111111{c{{l{e}}}{}{}}00000{c{{l{en}}}{}{}}00000{c{{l{eA`}}}{}{}}00000{cAb{}}00555````````{{cAd}Af{}}``66{ChCh}{{ce}Af{}{}}{{}Ch}{{ChAj}Al};:``::8877665:`4::{LbLb}3`{{LbAj}Al}={{LbBl}{{l{Ld`}}}}={{BlCj}{{l{LbCl}}}}```>><<;;::9>","c":[],"p":[[5,"TxIndexerConfig",45],[5,"TxIndexer",0],[8,"Error",960],[8,"Result",961],[10,"EventHandler",804],[6,"Result",962],[6,"TryFromPLAError",963],[6,"TryFromCSLError",964],[5,"TypeId",965],[5,"Private",966],[1,"unit"],[5,"ParseCurrencySymbol",25],[5,"Formatter",967],[8,"Result",967],[1,"str"],[6,"NetworkName",45],[6,"NetworkConfig",45],[5,"NetworkNameParseErr",45],[1,"bool"],[5,"Error",967],[6,"NodeAddress",45],[1,"u64"],[5,"String",968],[1,"tuple"],[6,"Option",969],[1,"usize"],[5,"Filter",785],[5,"RetryPolicy",911],[5,"ChainWellKnownInfo",970],[5,"Error",961],[5,"MagicArg",971],[5,"AddressArg",971],[5,"Config",972],[5,"Config",973],[5,"PgTypeInfo",974],[5,"CurrencySymbol",164],[5,"TokenName",164],[5,"TransactionHash",164],[5,"Ed25519PubKeyHash",164],[5,"ScriptHash",164],[5,"DatumHash",164],[5,"Slot",164],[5,"PlutusData",164],[5,"Credential",164],[5,"ChainPointer",164],[5,"StakingCredential",164],[5,"Address",164],[5,"AssetQuantity",164],[5,"Value",164],[5,"TransactionInput",164],[5,"OutputDatum",164],[5,"TransactionOutput",164],[5,"TxInInfo",164],[6,"Ordering",975],[10,"Error",976],[5,"Box",977],[5,"PgValueRef",978],[6,"IsNull",979],[8,"BoxDynError",980],[5,"PgArgumentBuffer",981],[6,"DBTypeConversionError",164],[6,"PlutusDataEncodingError",164],[6,"CurrencySymbol",982],[5,"TokenName",982],[5,"TransactionHash",983],[5,"Ed25519PubKeyHash",984],[5,"ScriptHash",985],[5,"DatumHash",986],[5,"JsError",987],[6,"Credential",988],[6,"PlutusData",989],[5,"ChainPointer",988],[6,"StakingCredential",988],[5,"Address",988],[5,"BigInt",990],[5,"Value",982],[5,"TransactionInput",983],[6,"OutputDatum",991],[5,"TransactionOutput",992],[5,"TxInInfo",992],[5,"SyncProgressTable",735],[8,"Result",980],[10,"Row",993],[5,"PgConnection",994],[6,"Error",980],[10,"ErrorPolicyProvider",765],[6,"ErrorPolicy",765],[5,"Config",995],[6,"Events",804],[17,"Error"],[6,"ChainEvent",824],[17,"Output"],[10,"Future",996],[5,"ChainEventTime",824],[5,"TransactionEventRecord",824],[5,"Event",997],[5,"ProgressTracker",935],[1,"f32"],[15,"ConfigPath",158],[15,"RollbackEvent",904],[15,"SyncProgressEvent",904],[15,"TransactionEvent",904]],"b":[[82,"impl-Display-for-NetworkName"],[83,"impl-Debug-for-NetworkName"],[85,"impl-Debug-for-NetworkNameParseErr"],[86,"impl-Display-for-NetworkNameParseErr"],[403,"impl-Debug-for-DBTypeConversionError"],[404,"impl-Display-for-DBTypeConversionError"],[412,"impl-Display-for-PlutusDataEncodingError"],[413,"impl-Debug-for-PlutusDataEncodingError"],[441,"impl-From%3CTryFromCSLError%3E-for-PlutusDataEncodingError"],[442,"impl-From%3CTryFromPLAError%3E-for-PlutusDataEncodingError"],[444,"impl-From%3CJsError%3E-for-PlutusDataEncodingError"]]}]\
+]'));
+if (typeof exports !== 'undefined') exports.searchIndex = searchIndex;
+else if (window.initSearch) window.initSearch(searchIndex);
diff --git a/artifacts/tx-indexer/settings.html b/artifacts/tx-indexer/settings.html
new file mode 100644
index 0000000..6de9a26
--- /dev/null
+++ b/artifacts/tx-indexer/settings.html
@@ -0,0 +1,2 @@
+use data_encoding::HEXLOWER;
+use plutus_ledger_api::v2::{
+ crypto::LedgerBytes,
+ script::{MintingPolicyHash, ScriptHash},
+ value::CurrencySymbol,
+};
+use std::str::FromStr;
+
+#[derive(Debug, Clone)]
+pub struct ParseCurrencySymbol(pub CurrencySymbol);
+
+impl FromStr for ParseCurrencySymbol {
+ type Err = &'static str;
+
+ fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+ Ok(ParseCurrencySymbol(CurrencySymbol::NativeToken(
+ MintingPolicyHash(ScriptHash(LedgerBytes(
+ HEXLOWER.decode(&s.to_owned().into_bytes()).unwrap(),
+ ))),
+ )))
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +
use crate::{
+ filter::Filter,
+ handler::{callback::EventHandler, retry::RetryPolicy},
+};
+use anyhow::anyhow;
+use core::str::FromStr;
+use oura::{sources::MagicArg, utils::ChainWellKnownInfo};
+use std::error::Error;
+use std::fmt;
+use std::fs::File;
+use std::io::BufReader;
+use strum_macros::Display;
+
+pub struct TxIndexerConfig<H: EventHandler> {
+ pub handler: H,
+ pub node_address: NodeAddress,
+ pub network: NetworkConfig,
+ /// Slot number and hash as hex string (optional).
+ /// If not provided, sync will begin from the tip of the chain.
+ pub since_slot: Option<(u64, String)>,
+ /// Minimum depth a block has to be from the tip for it to be considered "confirmed"
+ /// See: https://oura.txpipe.io/v1/advanced/rollback_buffer
+ pub safe_block_depth: usize,
+ // Filter transaction events by specific component(s).
+ pub event_filter: Filter,
+ /// Retry policy - how much to retry for each event callback failure
+ /// This only takes effect on ErrorPolicy for a particular error is `Retry`.
+ /// Once retries are exhausted, the handler will error (same treatment as ErrorPolicy::Exit)
+ pub retry_policy: RetryPolicy,
+}
+
+impl<H: EventHandler> TxIndexerConfig<H> {
+ #[allow(clippy::too_many_arguments)]
+ pub fn new(
+ handler: H,
+ node_address: NodeAddress,
+ network: NetworkConfig,
+ since_slot: Option<(u64, String)>,
+ safe_block_depth: usize,
+ event_filter: Filter,
+ retry_policy: RetryPolicy,
+ ) -> Self {
+ Self {
+ handler,
+ node_address,
+ network,
+ since_slot,
+ safe_block_depth,
+ event_filter,
+ retry_policy,
+ }
+ }
+}
+
+/// Simple description on how to connect to a local or remote node.
+/// Used to build Oura source config.
+pub enum NodeAddress {
+ /// Path to Unix node.socket
+ UnixSocket(String),
+ /// Hostname and port number for TCP connection to remote node
+ TcpAddress(String, u16),
+}
+
+/// Typed network magic restricted to specific networks fully supported by Oura.
+#[derive(Clone, Debug, Display)]
+pub enum NetworkName {
+ PREPROD,
+ PREVIEW,
+ MAINNET,
+}
+
+#[derive(Clone, Debug)]
+pub enum NetworkConfig {
+ ConfigPath {
+ node_config_path: String,
+ magic: u64,
+ },
+ WellKnown(NetworkName),
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct NetworkNameParseErr;
+
+impl fmt::Display for NetworkNameParseErr {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "provided string was not `preprod` or `preview` or `mainnet`".fmt(f)
+ }
+}
+impl Error for NetworkNameParseErr {}
+
+impl FromStr for NetworkName {
+ type Err = NetworkNameParseErr;
+ fn from_str(s: &str) -> Result<NetworkName, Self::Err> {
+ match &s.to_lowercase()[..] {
+ "preprod" => Ok(NetworkName::PREPROD),
+ "preview" => Ok(NetworkName::PREVIEW),
+ "mainnet" => Ok(NetworkName::MAINNET),
+ _ => Err(NetworkNameParseErr),
+ }
+ }
+}
+
+impl NetworkConfig {
+ pub fn to_magic_arg(&self) -> MagicArg {
+ MagicArg(match self {
+ NetworkConfig::WellKnown(network_name) => match network_name {
+ NetworkName::PREPROD => pallas::network::miniprotocols::PRE_PRODUCTION_MAGIC,
+ NetworkName::PREVIEW => pallas::network::miniprotocols::PREVIEW_MAGIC,
+ NetworkName::MAINNET => pallas::network::miniprotocols::MAINNET_MAGIC,
+ },
+ NetworkConfig::ConfigPath { magic, .. } => *magic,
+ })
+ }
+
+ pub fn to_chain_info(&self) -> Result<ChainWellKnownInfo, anyhow::Error> {
+ Ok(match self {
+ NetworkConfig::WellKnown(network_name) => match network_name {
+ NetworkName::PREPROD => ChainWellKnownInfo::preprod(),
+ NetworkName::PREVIEW => ChainWellKnownInfo::preview(),
+ NetworkName::MAINNET => ChainWellKnownInfo::mainnet(),
+ },
+ NetworkConfig::ConfigPath {
+ node_config_path, ..
+ } => {
+ let file = File::open(node_config_path.clone())
+ .map_err(|err| anyhow!("Chain Info not found at given path: {}", err))?;
+ let reader = BufReader::new(file);
+ serde_json::from_reader(reader).expect("Invalid JSON format for ChainWellKnownInfo")
+ }
+ })
+ }
+}
+
+// Encapsulating usage of deprecated stuff (impossible to construct struct without it).
+// This avoids having to put "#![allow(deprecated)]" on the top of this file.
+pub mod deprecation_usage {
+ #![allow(deprecated)]
+
+ use oura::mapper::Config as MapperConfig;
+ use oura::sources::n2c::Config as N2CConfig;
+ use oura::sources::n2n::Config as N2NConfig;
+ use oura::sources::{AddressArg, IntersectArg, MagicArg, PointArg};
+
+ pub fn n2c_config(
+ addr: AddressArg,
+ magic: MagicArg,
+ since_slot: Option<(u64, String)>,
+ safe_block_depth: usize,
+ ) -> N2CConfig {
+ N2CConfig {
+ address: addr,
+ magic: Some(magic),
+ intersect: since_slot
+ .map(|since_slot| IntersectArg::Point(PointArg(since_slot.0, since_slot.1))),
+ mapper: MapperConfig {
+ include_transaction_details: true,
+ ..Default::default()
+ },
+ min_depth: safe_block_depth,
+ retry_policy: None,
+ finalize: None,
+ // Deprecated fields
+ since: None,
+ well_known: None,
+ }
+ }
+
+ pub fn n2n_config(
+ addr: AddressArg,
+ magic: MagicArg,
+ since_slot: Option<(u64, String)>,
+ safe_block_depth: usize,
+ ) -> N2NConfig {
+ N2NConfig {
+ address: addr,
+ magic: Some(magic),
+ intersect: since_slot
+ .map(|since_slot| IntersectArg::Point(PointArg(since_slot.0, since_slot.1))),
+ mapper: MapperConfig {
+ include_transaction_details: true,
+ ..Default::default()
+ },
+ min_depth: safe_block_depth,
+ retry_policy: None,
+ finalize: None,
+ // Deprecated fields
+ since: None,
+ well_known: None,
+ }
+ }
+}
+
+pub use self::deprecation_usage::*;
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +
use cardano_serialization_lib as csl;
+use num_bigint::BigInt;
+use plutus_ledger_api as pla;
+use thiserror::Error;
+use tx_bakery::utils::{
+ csl_to_pla::{TryFromCSLError, TryToPLA},
+ pla_to_csl::{TryFromPLAError, TryToCSLWithDef},
+};
+
+#[derive(Error, Debug)]
+pub enum DBTypeConversionError {
+ #[error("Couldn't parse DB type, because some invariants weren't valid: {0}")]
+ InvariantBroken(String),
+
+ #[error("Cannot represent BigInt as PostgreSQL BIGINT type: {0}")]
+ BigIntConversion(num_bigint::TryFromBigIntError<BigInt>),
+
+ #[error(transparent)]
+ PlutusDataEncodingError(#[from] PlutusDataEncodingError),
+}
+
+//////////////////////
+/// CurrencySymbol
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.CurrencySymbol")]
+pub struct CurrencySymbol(pub Vec<u8>);
+
+impl From<pla::v2::value::CurrencySymbol> for CurrencySymbol {
+ fn from(item: pla::v2::value::CurrencySymbol) -> Self {
+ match item {
+ pla::v2::value::CurrencySymbol::Ada => CurrencySymbol(Vec::with_capacity(0)),
+ pla::v2::value::CurrencySymbol::NativeToken(pla::v2::script::MintingPolicyHash(
+ pla::v2::script::ScriptHash(pla::v2::crypto::LedgerBytes(bytes)),
+ )) => CurrencySymbol(bytes),
+ }
+ }
+}
+
+impl From<CurrencySymbol> for pla::v2::value::CurrencySymbol {
+ fn from(item: CurrencySymbol) -> Self {
+ let CurrencySymbol(bytes) = item;
+ if bytes.is_empty() {
+ pla::v2::value::CurrencySymbol::Ada
+ } else {
+ pla::v2::value::CurrencySymbol::NativeToken(pla::v2::script::MintingPolicyHash(
+ pla::v2::script::ScriptHash(pla::v2::crypto::LedgerBytes(bytes)),
+ ))
+ }
+ }
+}
+
+//////////////////////
+/// TokenName
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.TokenName")]
+pub struct TokenName(pub Vec<u8>);
+
+impl From<pla::v2::value::TokenName> for TokenName {
+ fn from(item: pla::v2::value::TokenName) -> Self {
+ TokenName(item.0 .0)
+ }
+}
+
+impl From<TokenName> for pla::v2::value::TokenName {
+ fn from(item: TokenName) -> Self {
+ pla::v2::value::TokenName(pla::v2::crypto::LedgerBytes(item.0))
+ }
+}
+
+//////////////////////
+/// TransactionHash
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.TransactionHash")]
+pub struct TransactionHash(pub Vec<u8>);
+
+impl From<pla::v2::transaction::TransactionHash> for TransactionHash {
+ fn from(item: pla::v2::transaction::TransactionHash) -> Self {
+ TransactionHash(item.0 .0)
+ }
+}
+
+impl From<TransactionHash> for pla::v2::transaction::TransactionHash {
+ fn from(item: TransactionHash) -> Self {
+ pla::v2::transaction::TransactionHash(pla::v2::crypto::LedgerBytes(item.0))
+ }
+}
+
+//////////////////////
+/// Ed25519PubKeyHash
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.Ed25519PubKeyHash")]
+pub struct Ed25519PubKeyHash(pub Vec<u8>);
+
+impl From<pla::v2::crypto::Ed25519PubKeyHash> for Ed25519PubKeyHash {
+ fn from(item: pla::v2::crypto::Ed25519PubKeyHash) -> Self {
+ Ed25519PubKeyHash(item.0 .0)
+ }
+}
+
+impl From<Ed25519PubKeyHash> for pla::v2::crypto::Ed25519PubKeyHash {
+ fn from(item: Ed25519PubKeyHash) -> Self {
+ pla::v2::crypto::Ed25519PubKeyHash(pla::v2::crypto::LedgerBytes(item.0))
+ }
+}
+
+//////////////////////
+/// ScriptHash
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.ScriptHash")]
+pub struct ScriptHash(pub Vec<u8>);
+
+impl From<pla::v2::script::ScriptHash> for ScriptHash {
+ fn from(item: pla::v2::script::ScriptHash) -> Self {
+ ScriptHash(item.0 .0)
+ }
+}
+
+impl From<ScriptHash> for pla::v2::script::ScriptHash {
+ fn from(item: ScriptHash) -> Self {
+ pla::v2::script::ScriptHash(pla::v2::crypto::LedgerBytes(item.0))
+ }
+}
+
+//////////////////////
+/// DatumHash
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.DatumHash")]
+pub struct DatumHash(pub Vec<u8>);
+
+impl From<pla::v2::datum::DatumHash> for DatumHash {
+ fn from(item: pla::v2::datum::DatumHash) -> Self {
+ DatumHash(item.0 .0)
+ }
+}
+
+impl From<DatumHash> for pla::v2::datum::DatumHash {
+ fn from(item: DatumHash) -> Self {
+ pla::v2::datum::DatumHash(pla::v2::crypto::LedgerBytes(item.0))
+ }
+}
+
+//////////////////////
+/// Slot
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[sqlx(type_name = "Plutus.Slot")]
+pub struct Slot(pub i64);
+
+impl From<u64> for Slot {
+ fn from(item: u64) -> Self {
+ Slot(item as i64)
+ }
+}
+
+impl From<&Slot> for u64 {
+ fn from(item: &Slot) -> Self {
+ item.0 as u64
+ }
+}
+
+//////////////////////
+/// PlutusData
+//////////////////////
+
+#[derive(Error, Debug)]
+pub enum PlutusDataEncodingError {
+ #[error(transparent)]
+ CSLConversionError(#[from] csl::error::JsError),
+
+ #[error(transparent)]
+ TryFromPLAError(#[from] TryFromPLAError),
+
+ #[error(transparent)]
+ TryFromCSLError(#[from] TryFromCSLError),
+}
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.PlutusData")]
+pub struct PlutusData(pub serde_json::Value);
+
+impl TryFrom<pla::plutus_data::PlutusData> for PlutusData {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: pla::plutus_data::PlutusData) -> Result<Self, Self::Error> {
+ Ok(PlutusData(
+ csl::plutus::decode_plutus_datum_to_json_value(
+ &item
+ .try_to_csl()
+ .map_err(PlutusDataEncodingError::TryFromPLAError)?,
+ csl::plutus::PlutusDatumSchema::DetailedSchema,
+ )
+ .map_err(PlutusDataEncodingError::CSLConversionError)?,
+ ))
+ }
+}
+
+impl TryFrom<PlutusData> for pla::plutus_data::PlutusData {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: PlutusData) -> Result<Self, Self::Error> {
+ Ok(csl::plutus::encode_json_value_to_plutus_datum(
+ item.0,
+ csl::plutus::PlutusDatumSchema::DetailedSchema,
+ )
+ .map_err(PlutusDataEncodingError::CSLConversionError)?
+ .try_to_pla()
+ .map_err(PlutusDataEncodingError::TryFromCSLError)?)
+ }
+}
+
+//////////////////////
+/// Credential
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.Credential")]
+pub struct Credential {
+ pub_key_hash: Option<Ed25519PubKeyHash>,
+ script_hash: Option<ScriptHash>,
+}
+
+impl From<pla::v2::address::Credential> for Credential {
+ fn from(item: pla::v2::address::Credential) -> Self {
+ match item {
+ pla::v2::address::Credential::PubKey(pkh) => Credential {
+ pub_key_hash: Some(pkh.into()),
+ script_hash: None,
+ },
+ pla::v2::address::Credential::Script(pla::v2::script::ValidatorHash(sh)) => {
+ Credential {
+ pub_key_hash: None,
+ script_hash: Some(sh.into()),
+ }
+ }
+ }
+ }
+}
+
+impl TryFrom<Credential> for pla::v2::address::Credential {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: Credential) -> Result<Self, Self::Error> {
+ Ok(match item {
+ Credential {
+ pub_key_hash: Some(pkh_db),
+ script_hash: None,
+ } => pla::v2::address::Credential::PubKey(pkh_db.into()),
+ Credential {
+ pub_key_hash: None,
+ script_hash: Some(sh_db),
+ } => pla::v2::address::Credential::Script(pla::v2::script::ValidatorHash(sh_db.into())),
+ _ => Err(DBTypeConversionError::InvariantBroken(
+ "DB Credential must have either 'pub_key_hash' or 'script_hash'".to_string(),
+ ))?,
+ })
+ }
+}
+
+//////////////////////
+/// ChainPointer
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.ChainPointer")]
+pub struct ChainPointer {
+ slot_num: i64,
+ tx_idx: i64,
+ cert_idx: i64,
+}
+
+impl TryFrom<pla::v2::address::ChainPointer> for ChainPointer {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: pla::v2::address::ChainPointer) -> Result<Self, Self::Error> {
+ Ok(ChainPointer {
+ slot_num: item
+ .slot_number
+ .0
+ .try_into()
+ .map_err(DBTypeConversionError::BigIntConversion)?,
+ tx_idx: item
+ .transaction_index
+ .0
+ .try_into()
+ .map_err(DBTypeConversionError::BigIntConversion)?,
+ cert_idx: item
+ .certificate_index
+ .0
+ .try_into()
+ .map_err(DBTypeConversionError::BigIntConversion)?,
+ })
+ }
+}
+
+impl From<ChainPointer> for pla::v2::address::ChainPointer {
+ fn from(item: ChainPointer) -> Self {
+ pla::v2::address::ChainPointer {
+ slot_number: pla::v2::address::Slot(BigInt::from(item.slot_num)),
+ transaction_index: pla::v2::address::TransactionIndex(BigInt::from(item.tx_idx)),
+ certificate_index: pla::v2::address::CertificateIndex(BigInt::from(item.cert_idx)),
+ }
+ }
+}
+
+//////////////////////
+/// StakingCredential
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.StakingCredential")]
+pub struct StakingCredential {
+ staking_hash: Option<Credential>,
+ staking_ptr: Option<ChainPointer>,
+}
+
+impl TryFrom<pla::v2::address::StakingCredential> for StakingCredential {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: pla::v2::address::StakingCredential) -> Result<Self, Self::Error> {
+ Ok(match item {
+ pla::v2::address::StakingCredential::Hash(cred) => StakingCredential {
+ staking_hash: Some(cred.into()),
+ staking_ptr: None,
+ },
+ pla::v2::address::StakingCredential::Pointer(ptr) => StakingCredential {
+ staking_hash: None,
+ staking_ptr: Some(ptr.try_into()?),
+ },
+ })
+ }
+}
+
+impl TryFrom<StakingCredential> for pla::v2::address::StakingCredential {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: StakingCredential) -> Result<Self, Self::Error> {
+ Ok(match item {
+ StakingCredential {
+ staking_hash: Some(cred),
+ staking_ptr: None,
+ } => pla::v2::address::StakingCredential::Hash(cred.try_into()?),
+ StakingCredential {
+ staking_hash: None,
+ staking_ptr: Some(ptr),
+ } => pla::v2::address::StakingCredential::Pointer(ptr.into()),
+
+ _ => Err(DBTypeConversionError::InvariantBroken(
+ "DB StakingCredential must have either 'staking_hash' or 'staking_ptr'".to_string(),
+ ))?,
+ })
+ }
+}
+
+//////////////////////
+/// Address
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.Address")]
+pub struct Address {
+ credential: Credential,
+ staking_credential: Option<StakingCredential>,
+}
+
+impl TryFrom<pla::v2::address::Address> for Address {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: pla::v2::address::Address) -> Result<Self, Self::Error> {
+ Ok(Address {
+ credential: item.credential.into(),
+ staking_credential: item
+ .staking_credential
+ .map(StakingCredential::try_from)
+ .transpose()?,
+ })
+ }
+}
+
+impl TryFrom<Address> for pla::v2::address::Address {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: Address) -> Result<Self, Self::Error> {
+ Ok(pla::v2::address::Address {
+ credential: item.credential.try_into()?,
+ staking_credential: item
+ .staking_credential
+ .map(pla::v2::address::StakingCredential::try_from)
+ .transpose()?,
+ })
+ }
+}
+
+//////////////////////
+/// AssetQuantity
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.AssetQuantity")]
+pub struct AssetQuantity {
+ currency_symbol: CurrencySymbol,
+ token_name: TokenName,
+ amount: i64,
+}
+
+impl
+ TryFrom<(
+ pla::v2::value::CurrencySymbol,
+ pla::v2::value::TokenName,
+ BigInt,
+ )> for AssetQuantity
+{
+ type Error = DBTypeConversionError;
+
+ fn try_from(
+ item: (
+ pla::v2::value::CurrencySymbol,
+ pla::v2::value::TokenName,
+ BigInt,
+ ),
+ ) -> Result<Self, Self::Error> {
+ Ok(AssetQuantity {
+ currency_symbol: item.0.into(),
+ token_name: item.1.into(),
+ amount: item
+ .2
+ .try_into()
+ .map_err(DBTypeConversionError::BigIntConversion)?,
+ })
+ }
+}
+
+impl From<AssetQuantity>
+ for (
+ pla::v2::value::CurrencySymbol,
+ pla::v2::value::TokenName,
+ BigInt,
+ )
+{
+ fn from(item: AssetQuantity) -> Self {
+ (
+ item.currency_symbol.into(),
+ item.token_name.into(),
+ item.amount.into(),
+ )
+ }
+}
+
+//////////////////////
+/// Value
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.Value")]
+pub struct Value(pub Vec<AssetQuantity>);
+
+impl TryFrom<pla::v2::value::Value> for Value {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: pla::v2::value::Value) -> Result<Self, Self::Error> {
+ let assets = item
+ .0
+ .iter()
+ .flat_map(|(cs, assets)| {
+ assets
+ .iter()
+ .map(|(tn, amount)| {
+ AssetQuantity::try_from((cs.to_owned(), tn.to_owned(), amount.to_owned()))
+ })
+ .collect::<Vec<_>>()
+ })
+ .collect::<Result<Vec<AssetQuantity>, DBTypeConversionError>>()?;
+
+ Ok(Value(assets))
+ }
+}
+
+impl From<Value> for pla::v2::value::Value {
+ fn from(item: Value) -> Self {
+ item.0.into_iter().fold(
+ pla::v2::value::Value::new(),
+ |value,
+ AssetQuantity {
+ currency_symbol,
+ token_name,
+ amount,
+ }| {
+ value.insert_token(¤cy_symbol.into(), &token_name.into(), &amount.into())
+ },
+ )
+ }
+}
+
+//////////////////////
+/// TransactionInput
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.TransactionInput")]
+pub struct TransactionInput {
+ tx_id: TransactionHash,
+ tx_idx: i64,
+}
+
+impl TryFrom<pla::v2::transaction::TransactionInput> for TransactionInput {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: pla::v2::transaction::TransactionInput) -> Result<Self, Self::Error> {
+ Ok(TransactionInput {
+ tx_id: item.transaction_id.into(),
+ tx_idx: item
+ .index
+ .try_into()
+ .map_err(DBTypeConversionError::BigIntConversion)?,
+ })
+ }
+}
+
+impl From<TransactionInput> for pla::v2::transaction::TransactionInput {
+ fn from(item: TransactionInput) -> Self {
+ pla::v2::transaction::TransactionInput {
+ transaction_id: item.tx_id.into(),
+ index: item.tx_idx.into(),
+ }
+ }
+}
+
+//////////////////////
+/// OutputDatum
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.OutputDatum")]
+pub struct OutputDatum {
+ datum_hash: Option<DatumHash>,
+ inline_datum: Option<PlutusData>,
+}
+
+impl TryFrom<pla::v2::datum::OutputDatum> for OutputDatum {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: pla::v2::datum::OutputDatum) -> Result<Self, Self::Error> {
+ Ok(match item {
+ pla::v2::datum::OutputDatum::DatumHash(dh) => OutputDatum {
+ datum_hash: Some(dh.into()),
+ inline_datum: None,
+ },
+ pla::v2::datum::OutputDatum::InlineDatum(pla::v2::datum::Datum(datum)) => OutputDatum {
+ datum_hash: None,
+ inline_datum: Some(datum.try_into()?),
+ },
+ pla::v2::datum::OutputDatum::None => OutputDatum {
+ datum_hash: None,
+ inline_datum: None,
+ },
+ })
+ }
+}
+
+impl TryFrom<OutputDatum> for pla::v2::datum::OutputDatum {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: OutputDatum) -> Result<Self, Self::Error> {
+ Ok(match item {
+ OutputDatum {
+ datum_hash: Some(dh_db),
+ ..
+ } => pla::v2::datum::OutputDatum::DatumHash(dh_db.into()),
+ OutputDatum {
+ inline_datum: Some(datum_db),
+ ..
+ } => pla::v2::datum::OutputDatum::InlineDatum(pla::v2::datum::Datum(
+ datum_db.try_into()?,
+ )),
+ _ => pla::v2::datum::OutputDatum::None,
+ })
+ }
+}
+
+//////////////////////
+/// TransactionOutput
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.TransactionOutput")]
+pub struct TransactionOutput {
+ address: Address,
+ assets: Value,
+ datum: OutputDatum,
+ reference_script: Option<ScriptHash>,
+}
+
+impl TryFrom<pla::v2::transaction::TransactionOutput> for TransactionOutput {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: pla::v2::transaction::TransactionOutput) -> Result<Self, Self::Error> {
+ Ok(TransactionOutput {
+ address: item.address.try_into()?,
+ assets: item.value.try_into()?,
+ datum: item.datum.try_into()?,
+ reference_script: item.reference_script.map(ScriptHash::from),
+ })
+ }
+}
+
+impl TryFrom<TransactionOutput> for pla::v2::transaction::TransactionOutput {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: TransactionOutput) -> Result<Self, Self::Error> {
+ Ok(pla::v2::transaction::TransactionOutput {
+ address: item.address.try_into()?,
+ value: item.assets.into(),
+ datum: item.datum.try_into()?,
+ reference_script: item.reference_script.map(pla::v2::script::ScriptHash::from),
+ })
+ }
+}
+
+//////////////////////
+/// TxInInfo
+//////////////////////
+
+#[derive(sqlx::Type, Clone, Debug, PartialEq, Eq)]
+#[sqlx(type_name = "Plutus.TxInInfo")]
+pub struct TxInInfo {
+ reference: TransactionInput,
+ output: TransactionOutput,
+}
+
+impl TryFrom<pla::v2::transaction::TxInInfo> for TxInInfo {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: pla::v2::transaction::TxInInfo) -> Result<Self, Self::Error> {
+ Ok(TxInInfo {
+ reference: item.reference.try_into()?,
+ output: item.output.try_into()?,
+ })
+ }
+}
+
+impl TryFrom<TxInInfo> for pla::v2::transaction::TxInInfo {
+ type Error = DBTypeConversionError;
+
+ fn try_from(item: TxInInfo) -> Result<Self, Self::Error> {
+ Ok(pla::v2::transaction::TxInInfo {
+ reference: item.reference.into(),
+ output: item.output.try_into()?,
+ })
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +
use data_encoding::HEXLOWER;
+use sqlx::{FromRow, PgConnection};
+use tracing::{info_span, span, Instrument, Level};
+
+#[derive(Clone, Debug, FromRow, Eq, PartialEq)]
+pub struct SyncProgressTable {
+ pub block_slot: i64,
+ pub block_hash: Vec<u8>,
+}
+
+impl SyncProgressTable {
+ pub fn new(block_slot: u64, block_hash: String) -> Result<SyncProgressTable, anyhow::Error> {
+ Ok(SyncProgressTable {
+ block_slot: block_slot as i64,
+ block_hash: HEXLOWER.decode(block_hash.as_bytes())?,
+ })
+ }
+
+ /// Obtain the sync status of the DB
+ pub async fn get(conn: &mut PgConnection) -> Result<Option<Self>, sqlx::Error> {
+ let span = info_span!("Get SyncProgress");
+ // Get existing entity
+ sqlx::query_as::<_, Self>("SELECT block_slot, block_hash FROM sync_progress")
+ .fetch_optional(conn)
+ .instrument(span)
+ .await
+ }
+
+ /// Save a new entity to the database.
+ pub async fn store(&self, conn: &mut PgConnection) -> Result<(), sqlx::Error> {
+ let span = span!(Level::INFO, "Store SyncProgress", ?self.block_slot);
+ // Insert new entity
+ sqlx::query(
+ r#"
+ INSERT INTO sync_progress (block_slot, block_hash)
+ VALUES ($1, $2)
+ ON CONFLICT (id)
+ DO UPDATE SET
+ block_slot = EXCLUDED.block_slot,
+ block_hash = EXCLUDED.block_hash
+ "#,
+ )
+ .bind(self.block_slot)
+ .bind(self.block_hash.clone())
+ .execute(conn)
+ .instrument(span)
+ .await?;
+
+ Ok(())
+ }
+
+ pub async fn get_or(
+ conn: &mut PgConnection,
+ since_slot: Option<u64>,
+ since_block: Option<String>,
+ ) -> Result<Option<(u64, String)>, anyhow::Error> {
+ let sync_status = Self::get(conn).await?;
+
+ Ok(sync_status
+ .map(
+ |Self {
+ block_slot,
+ block_hash,
+ }| (block_slot as u64, HEXLOWER.encode(&block_hash)),
+ )
+ .or(since_slot.zip(since_block)))
+ }
+}
+
/// Specify what the indexer event handler should do for specific errors. See: `ErrorPolicyProvider`.
+/// The idea is that an error type, `E`, implements `ErrorPolicyProvider`.
+/// Based on the different variants of `E`, different `ErrorPolicy` can be returned, which influences
+/// the behavior of the event handler.
+pub enum ErrorPolicy<E> {
+ /// Indicate the callback operation should be retried. Also see: `RetryPolicy`.
+ Retry,
+ /// Indicate that the error should be ignored, go to next event.
+ Skip,
+ /// Indicate that the event handler should exit with error.
+ Exit,
+ /// Indicate that the event handler should call given error handling function with the error.
+ Call(fn(E) -> ()),
+}
+
+/// Trait that can be implemented for custom error types.
+/// Different variants in said error types can then be given different `ErrorPolicy` assignments.
+pub trait ErrorPolicyProvider
+where
+ Self: Sized,
+{
+ fn get_error_policy(&self) -> ErrorPolicy<Self>;
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +
use cardano_serialization_lib as csl;
+use oura::filters::selection::{Config, Predicate};
+use plutus_ledger_api::v2::{script::MintingPolicyHash, value::CurrencySymbol};
+use tx_bakery::utils::pla_to_csl::TryFromPLAWithDef;
+
+/// Interesting transaction components to look for when filtering transactions
+/// relevant to the protocol.
+/// Set curr_symbols to empty vectors to handle any transaction event indiscriminately.
+pub struct Filter {
+ pub curr_symbols: Vec<CurrencySymbol>,
+}
+
+// We only obtain Transaction events that contain the policy in the output
+// NOTE: Must enable 'include_transaction_details' in oura Mapper config.
+impl Filter {
+ pub fn to_selection_config(self) -> Config {
+ Config {
+ check: Predicate::AnyOf(vec![
+ Predicate::VariantIn(vec!["RollBack".to_string(), "Block".to_string()]),
+ Predicate::AllOf(vec![
+ Predicate::VariantIn(vec!["Transaction".to_string()]),
+ if self.curr_symbols.is_empty() {
+ ALWAYS_TRUE
+ } else {
+ Predicate::AnyOf(
+ self.curr_symbols
+ .into_iter()
+ .map(serialize_cur_sym)
+ .map(Predicate::PolicyEquals)
+ .collect(),
+ )
+ },
+ ]),
+ ]),
+ }
+ }
+}
+
+// Filter predicate that always succeeds.
+const ALWAYS_TRUE: Predicate = Predicate::AllOf(vec![]);
+
+fn serialize_cur_sym(cur_sym: CurrencySymbol) -> String {
+ match cur_sym {
+ CurrencySymbol::Ada => String::new(),
+ CurrencySymbol::NativeToken(MintingPolicyHash(script_hash)) => {
+ csl::crypto::ScriptHash::try_from_pla(&script_hash)
+ .unwrap()
+ .to_hex()
+ }
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +
use ::oura::model::{MintRecord, OutputAssetRecord};
+use anyhow::Context;
+use cardano_serialization_lib as csl;
+use data_encoding::HEXLOWER;
+use num_bigint::BigInt;
+use plutus_ledger_api::v2::{
+ address::Address,
+ crypto::LedgerBytes,
+ datum::{Datum, DatumHash},
+ script::{MintingPolicyHash, ScriptHash},
+ transaction::TransactionHash,
+ value::{CurrencySymbol, TokenName, Value},
+};
+use std::fmt::Debug;
+use tx_bakery::utils::csl_to_pla::TryToPLA;
+
+#[derive(thiserror::Error, Debug)]
+pub enum OuraParseError {
+ #[error(transparent)]
+ ParseError(#[from] anyhow::Error),
+
+ #[error("Unable to convert current time: {0}")]
+ TimeConversionError(tx_bakery::error::Error),
+}
+
+/// Convert an Oura transaction record type to its plutus-ledger-api counterpart
+pub trait FromOura<T> {
+ fn from_oura(value: T) -> Result<Self, OuraParseError>
+ where
+ Self: Sized;
+}
+
+impl FromOura<String> for LedgerBytes {
+ fn from_oura(value: String) -> Result<Self, OuraParseError> {
+ Ok(LedgerBytes(
+ HEXLOWER
+ .decode(&value.clone().into_bytes()[..])
+ .with_context(|| "Parsing LedgerBytes from Oura")?,
+ ))
+ }
+}
+
+impl FromOura<String> for TransactionHash {
+ fn from_oura(value: String) -> Result<Self, OuraParseError> {
+ Ok(TransactionHash(
+ LedgerBytes::from_oura(value).with_context(|| "Parsing TransactionHash from Oura")?,
+ ))
+ }
+}
+
+impl FromOura<String> for DatumHash {
+ fn from_oura(value: String) -> Result<Self, OuraParseError> {
+ Ok(DatumHash(LedgerBytes::from_oura(value)?))
+ }
+}
+
+impl FromOura<String> for CurrencySymbol {
+ fn from_oura(value: String) -> Result<Self, OuraParseError> {
+ Ok(if value.is_empty() {
+ CurrencySymbol::Ada
+ } else {
+ CurrencySymbol::NativeToken(MintingPolicyHash(ScriptHash(LedgerBytes::from_oura(
+ value,
+ )?)))
+ })
+ }
+}
+
+impl FromOura<String> for TokenName {
+ fn from_oura(value: String) -> Result<Self, OuraParseError> {
+ Ok(if value.is_empty() {
+ TokenName::ada()
+ } else {
+ TokenName(LedgerBytes::from_oura(value)?)
+ })
+ }
+}
+
+impl FromOura<serde_json::Value> for Datum {
+ fn from_oura(value: serde_json::Value) -> Result<Self, OuraParseError> {
+ let csl_plutus_data = csl::plutus::encode_json_value_to_plutus_datum(
+ value,
+ csl::plutus::PlutusDatumSchema::DetailedSchema,
+ )
+ .with_context(|| "Parsing Datum from Oura")?;
+
+ Ok(Datum(
+ csl_plutus_data
+ .try_to_pla()
+ .with_context(|| "Parsing Datum from Oura")?,
+ ))
+ }
+}
+
+impl FromOura<String> for Address {
+ fn from_oura(value: String) -> Result<Self, OuraParseError> {
+ let csl_addr = csl::address::Address::from_bech32(&value)
+ .or_else(|_| {
+ csl::address::ByronAddress::from_base58(&value)
+ .map(|byron_addr| byron_addr.to_address())
+ })
+ .with_context(|| "Parsing Address from Oura")?;
+
+ Ok(csl_addr
+ .try_to_pla()
+ .with_context(|| "Parsing Address from Oura")?)
+ }
+}
+
+impl FromOura<Vec<OutputAssetRecord>> for Value {
+ fn from_oura(value: Vec<OutputAssetRecord>) -> Result<Self, OuraParseError> {
+ value.iter().try_fold(Value::new(), |acc, x| {
+ let amt = BigInt::from(x.amount);
+ Ok(acc.insert_token(
+ &CurrencySymbol::from_oura(x.policy.clone())?,
+ &TokenName::from_oura(x.asset.clone())?,
+ &amt,
+ ))
+ })
+ }
+}
+
+impl FromOura<Vec<MintRecord>> for Value {
+ fn from_oura(value: Vec<MintRecord>) -> Result<Self, OuraParseError> {
+ value.iter().try_fold(Value::new(), |acc, x| {
+ let amt = BigInt::from(x.quantity);
+ Ok(acc.insert_token(
+ &CurrencySymbol::from_oura(x.policy.clone())?,
+ &TokenName::from_oura(x.asset.clone())?,
+ &amt,
+ ))
+ })
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +
use crate::{
+ error::ErrorPolicyProvider,
+ handler::{
+ chain_event::ChainEvent,
+ retry::{perform_with_retry, RetryPolicy},
+ },
+ progress_tracker::ProgressTracker,
+};
+use oura::{
+ pipelining::{BootstrapResult, SinkProvider, StageReceiver},
+ utils::Utils,
+};
+use std::{future::Future, sync::Arc};
+use strum_macros::Display;
+use tokio::runtime::Runtime;
+use tracing::{event, span, Instrument, Level};
+
+pub trait EventHandler
+where
+ Self: Clone + Send + 'static,
+{
+ type Error: std::error::Error + ErrorPolicyProvider;
+
+ fn handle(&self, event: ChainEvent) -> impl Future<Output = Result<(), Self::Error>>;
+}
+
+/// This is a custom made sink for Oura. Based on a callback function.
+/// The idea is similar to a webhook, but instead of calling a web endpoint - we call a function directly.
+pub(crate) struct Callback<H: EventHandler> {
+ pub(crate) handler: H,
+ pub(crate) retry_policy: RetryPolicy,
+ pub(crate) utils: Arc<Utils>,
+ pub(crate) progress_tracker: Option<ProgressTracker>,
+}
+
+impl<H: EventHandler> Callback<H> {
+ pub fn new(
+ handler: H,
+ retry_policy: RetryPolicy,
+ utils: Arc<Utils>,
+ progress_tracker: Option<ProgressTracker>,
+ ) -> Self {
+ Self {
+ handler,
+ retry_policy,
+ utils,
+ progress_tracker,
+ }
+ }
+}
+
+impl<H: EventHandler> SinkProvider for Callback<H> {
+ fn bootstrap(&self, input: StageReceiver) -> BootstrapResult {
+ let span = span!(Level::DEBUG, "Callback::bootstrap");
+ let _enter = span.enter();
+
+ let retry_policy = self.retry_policy;
+ let utils = self.utils.clone();
+ let handler = self.handler.clone();
+ let progress_tracker = self.progress_tracker.clone();
+
+ let handle = span!(Level::DEBUG, "SpawningThread").in_scope(|| {
+ std::thread::spawn(move || {
+ let span = span!(Level::DEBUG, "EventHandlingThread");
+ let _enter = span.enter();
+
+ // Running async function sycnhronously within another thread.
+ let rt = Runtime::new().unwrap();
+ rt.block_on(handle_event(
+ handler,
+ input,
+ &retry_policy,
+ utils,
+ progress_tracker,
+ ))
+ .map_err(|err| {
+ event!(Level::ERROR, label=%Events::EventHandlerFailure, ?err);
+ err
+ })
+ .expect("request loop failed");
+ })
+ });
+
+ Ok(handle)
+ }
+}
+
+// Handle a sequence of events transmitted at once.
+async fn handle_event<'a, H: EventHandler>(
+ handler: H,
+ input: StageReceiver,
+ retry_policy: &RetryPolicy,
+ utils: Arc<Utils>,
+ mut progress_tracker: Option<ProgressTracker>,
+) -> Result<(), H::Error> {
+ let span = span!(Level::DEBUG, "handle_event");
+ let _enter = span.enter();
+ for chain_event in input.into_iter() {
+ let span = span!(
+ Level::DEBUG,
+ "HandlingEvent",
+ context=?chain_event.context
+ );
+ // Have to clone twice here to please the borrow checker...
+ perform_with_retry(
+ &handler,
+ chain_event.clone(),
+ retry_policy,
+ &mut progress_tracker,
+ )
+ .instrument(span)
+ .await
+ // Notify progress to the pipeline.
+ .map(|_| utils.track_sink_progress(&chain_event))?;
+ // ^ This will exit the loop if an error is returned.
+ // After all, `perform_with_retry` will only return error if all other options,
+ // based on `ErrorPolicy`, were exhausted.
+ }
+ // All chain events in this sequence have been handled.
+ Ok(())
+}
+
+#[derive(Display)]
+pub enum Events {
+ EventHandlerFailure,
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +
use crate::{
+ from_oura::{FromOura, OuraParseError},
+ progress_tracker::ProgressTracker,
+};
+use num_bigint::BigInt;
+use oura::model as oura;
+use plutus_ledger_api::v2::{
+ address::Address,
+ datum::{Datum, DatumHash, OutputDatum},
+ transaction::{TransactionHash, TransactionInput, TransactionOutput, TxInInfo},
+ value::Value,
+};
+use std::fmt::Debug;
+use std::{collections::HashMap, sync::atomic::Ordering};
+use tracing::{event, Level};
+
+/// Indication of when an event happened in the context of the chain.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct ChainEventTime {
+ pub block_number: u64,
+ pub block_hash: String,
+ pub slot: u64,
+}
+
+/// Chain events that the indexer is configured to produce.
+#[derive(Clone, Debug, PartialEq)]
+pub enum ChainEvent {
+ /// A filtered transaction was confirmed
+ TransactionEvent {
+ time: ChainEventTime,
+ transaction: TransactionEventRecord,
+ },
+
+ /// Rollback event occurred
+ RollbackEvent { block_slot: u64, block_hash: String },
+
+ /// Chain syncronisation progressed
+ SyncProgressEvent {
+ block_slot: u64,
+ block_hash: String,
+ percentage: f32,
+ },
+}
+
+/// Details on an transaction event (excluding unnecessary information).
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TransactionEventRecord {
+ pub hash: TransactionHash,
+ pub fee: u64,
+ pub size: u32,
+
+ pub inputs: Vec<TransactionInput>,
+ pub outputs: Vec<TxInInfo>,
+ pub mint: Value,
+
+ pub plutus_data: HashMap<DatumHash, Datum>,
+ // TODO(chase): Which of these would be realistically be interested in?
+ // pub vkey_witnesses: Option<Vec<VKeyWitnessRecord>>,
+ // pub native_witnesses: Option<Vec<NativeWitnessRecord>>,
+ // pub plutus_witnesses: Option<Vec<PlutusWitnessRecord>>,
+ // pub plutus_redeemers: Option<Vec<PlutusRedeemerRecord>>,
+}
+
+pub fn parse_oura_event(
+ ev: oura::Event,
+ progress_tracker: &mut Option<ProgressTracker>,
+) -> Result<Option<ChainEvent>, OuraParseError> {
+ Ok(match ev.data {
+ oura::EventData::Transaction(tx_rec) => {
+ event!(Level::DEBUG, label="TransactionEvent", transaction_record=?tx_rec);
+
+ Some(ChainEvent::TransactionEvent {
+ time: ChainEventTime {
+ // These unwraps should not fail.
+ block_hash: ev.context.block_hash.unwrap(),
+ block_number: ev.context.block_number.unwrap(),
+ slot: ev.context.slot.unwrap(),
+ },
+ transaction: TransactionEventRecord::from_oura(tx_rec)?,
+ })
+ }
+ oura::EventData::RollBack {
+ block_slot,
+ block_hash,
+ } => {
+ event!(Level::DEBUG, label="RollbackEvent", block_slot=?block_slot, block_hash=?block_hash);
+ Some(ChainEvent::RollbackEvent {
+ block_slot,
+ block_hash,
+ })
+ }
+ oura::EventData::Block(block_rec) => {
+ event!(Level::DEBUG, label="BlockEvent", block_record=?block_rec);
+ match progress_tracker {
+ Some(progress_tracker) => {
+ let block_slot = block_rec.slot;
+ let block_hash = block_rec.hash;
+
+ let percentage = progress_tracker.get_percentage(block_slot)?;
+
+ let throttled_sync_progress = (percentage * 10.0) as usize;
+ let is_updated = progress_tracker
+ .sync_progress
+ .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev_status| {
+ if prev_status < throttled_sync_progress {
+ Some(throttled_sync_progress)
+ } else {
+ None
+ }
+ })
+ .is_ok();
+
+ if is_updated {
+ event!(
+ Level::INFO,
+ percentage = format!("{:.1}%", percentage),
+ ?block_slot,
+ ?block_hash,
+ label = "Chain synchronization progress"
+ );
+ }
+
+ Some(ChainEvent::SyncProgressEvent {
+ percentage,
+ block_slot,
+ block_hash,
+ })
+ }
+
+ None => Some(ChainEvent::SyncProgressEvent {
+ percentage: 100.0,
+ block_slot: block_rec.slot,
+ block_hash: block_rec.hash,
+ }),
+ }
+ }
+ _ => panic!("absurd: Indexer filter should only allow transaction event variant."),
+ })
+}
+
+impl FromOura<oura::TransactionRecord> for TransactionEventRecord {
+ fn from_oura(tx: oura::TransactionRecord) -> Result<TransactionEventRecord, OuraParseError> {
+ Ok(TransactionEventRecord {
+ hash: TransactionHash::from_oura(tx.hash.clone())?,
+ fee: tx.fee,
+ size: tx.size,
+ // All these unwraps should succeed since we enable `include_transaction_details`
+ // in the mapper config.
+ inputs: tx
+ .inputs
+ .unwrap()
+ .into_iter()
+ .map(|oura::TxInputRecord { tx_id, index }| {
+ Ok(TransactionInput {
+ transaction_id: TransactionHash::from_oura(tx_id)?,
+ index: BigInt::from(index),
+ })
+ })
+ .collect::<Result<_, OuraParseError>>()?,
+ outputs: tx
+ .outputs
+ .unwrap()
+ .into_iter()
+ .enumerate()
+ .map(
+ |(
+ index,
+ oura::TxOutputRecord {
+ address,
+ amount,
+ assets,
+ datum_hash,
+ inline_datum,
+ },
+ )| {
+ let reference = TransactionInput {
+ transaction_id: TransactionHash::from_oura(tx.hash.clone())?,
+ index: index.into(),
+ };
+ let output = TransactionOutput {
+ address: Address::from_oura(address)?,
+ datum: match (datum_hash, inline_datum) {
+ (None, None) => OutputDatum::None,
+ (_, Some(datm)) => {
+ OutputDatum::InlineDatum(Datum::from_oura(datm.plutus_data)?)
+ }
+ (Some(dh), _) => OutputDatum::DatumHash(DatumHash::from_oura(dh)?),
+ },
+ // NOTE(chase): There is currently no way to know about reference scripts with Oura.
+ reference_script: None,
+ value: Value::ada_value(&BigInt::from(amount))
+ + Value::from_oura(assets.unwrap_or_default())?,
+ };
+
+ Ok(TxInInfo { reference, output })
+ },
+ )
+ .collect::<Result<_, OuraParseError>>()?,
+ mint: tx.mint.map_or(Ok(Value::new()), Value::from_oura)?,
+ plutus_data: tx
+ .plutus_data
+ .unwrap_or_default()
+ .into_iter()
+ .map(
+ |oura::PlutusDatumRecord {
+ plutus_data,
+ datum_hash,
+ }| {
+ Ok((
+ DatumHash::from_oura(datum_hash)?,
+ Datum::from_oura(plutus_data)?,
+ ))
+ },
+ )
+ .collect::<Result<_, OuraParseError>>()?,
+ })
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +
use crate::{
+ error::{ErrorPolicy, ErrorPolicyProvider},
+ handler::{callback::EventHandler, chain_event::parse_oura_event},
+ progress_tracker::ProgressTracker,
+};
+use oura::model as oura;
+use std::{fmt::Debug, ops::Mul, time::Duration};
+use strum_macros::Display;
+use tracing::{event, span, Instrument, Level};
+
+/// Influence retrying behavior.
+/// i.e How many times and how often a failed operation should be retried.
+/// Given we are dealing with `ErrorPolicy::Retry`
+#[derive(Debug, Copy, Clone)]
+pub struct RetryPolicy {
+ pub max_retries: u32,
+ pub backoff_unit: Duration,
+ pub backoff_factor: u32,
+ pub max_backoff: Duration,
+}
+
+#[derive(Display)]
+enum EventOutcome {
+ Success,
+ FailureExit,
+ FailureSkip,
+ FailureRetry,
+ RetriesExhausted,
+ RetryBackoff,
+}
+
+impl Default for RetryPolicy {
+ fn default() -> Self {
+ Self {
+ max_retries: 20,
+ backoff_unit: Duration::from_millis(5_000),
+ backoff_factor: 2,
+ max_backoff: Duration::from_millis(20 * 5_000),
+ }
+ }
+}
+
+fn compute_backoff_delay(policy: &RetryPolicy, retry: u32) -> Duration {
+ let units = policy.backoff_factor.pow(retry);
+ let backoff = policy.backoff_unit.mul(units);
+ core::cmp::min(backoff, policy.max_backoff)
+}
+
+/// Wrap an operation with retry logic.
+/// Retrying is based on ErrorPolicy associated with particular error.
+/// Retries are only performed for ErrorPolicy::Retry - other errors won't cause invocation of given operation again.
+pub(crate) async fn perform_with_retry<H: EventHandler>(
+ handler: &H,
+ oura_event: oura::Event,
+ policy: &RetryPolicy,
+ progress_tracker: &mut Option<ProgressTracker>,
+) -> Result<(), H::Error> {
+ let span = span!(Level::DEBUG, "perform_with_retry");
+ let _enter = span.enter();
+
+ match parse_oura_event(oura_event, progress_tracker) {
+ Ok(Some(event)) => {
+ // The retry logic is based on:
+ // https://github.com/txpipe/oura/blob/27fb7e876471b713841d96e292ede40101b151d7/src/utils/retry.rs
+ let mut retry = 0;
+
+ loop {
+ // TODO(szg251): Handle errors properly
+ let span = span!(Level::DEBUG, "TryingOperation", retry_count = retry);
+ let res = async {
+ let result = handler.handle(event.clone())
+ .instrument(span!(Level::DEBUG, "UserDefinedHandler")).await;
+
+ match result {
+ Ok(_) => {
+ event!(Level::DEBUG, label=%EventOutcome::Success);
+ Some(Ok(()))
+ }
+ Err(err) => match err.get_error_policy() {
+ ErrorPolicy::Exit => {
+ event!(Level::ERROR, label=%EventOutcome::FailureExit);
+ Some(Err(err))
+ }
+ ErrorPolicy::Skip => {
+ event!(Level::WARN, label=%EventOutcome::FailureSkip, err=?err);
+ Some(Ok(()))
+ }
+ ErrorPolicy::Call(err_f) => span!(Level::WARN, "OperationFailureCall").in_scope(|| {
+ err_f(err);
+ Some(Ok(()))
+ }),
+ ErrorPolicy::Retry if retry < policy.max_retries => {
+ event!(Level::WARN, label=%EventOutcome::FailureRetry, err=?err);
+
+ retry += 1;
+
+ let backoff = compute_backoff_delay(policy, retry);
+
+ event!(Level::DEBUG, label=%EventOutcome::RetryBackoff, backoff_secs=backoff.as_secs());
+
+ std::thread::sleep(backoff);
+
+ None
+ }
+ _ => {
+ event!(Level::DEBUG, label=%EventOutcome::RetriesExhausted);
+ Some(Err(err))
+ }
+ },
+ }
+ }
+ .instrument(span)
+ .await;
+
+ if let Some(res) = res {
+ break res;
+ }
+ }
+ }
+ Ok(None) => Ok(()),
+ Err(err) => {
+ event!(Level::ERROR, err = ?err);
+
+ Ok(())
+ }
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +
use crate::{
+ config::{n2c_config, n2n_config, NodeAddress, TxIndexerConfig},
+ handler::callback::{Callback, EventHandler},
+ progress_tracker::ProgressTracker,
+};
+use anyhow::Result;
+use oura::{
+ pipelining::{FilterProvider, SinkProvider, SourceProvider},
+ sources::{AddressArg, BearerKind},
+ utils::{Utils, WithUtils},
+ Error,
+};
+use std::sync::Arc;
+use std::thread::JoinHandle;
+use tracing::{span, Level};
+
+// Structure holding the thread handles associated to the indexer. These threads are never-ending.
+pub struct TxIndexer {
+ pub source_handle: JoinHandle<()>,
+ pub filter_handle: JoinHandle<()>,
+ pub sink_handle: JoinHandle<()>,
+}
+
+impl TxIndexer {
+ // This is based on: https://github.com/txpipe/oura/blob/27fb7e876471b713841d96e292ede40101b151d7/src/bin/oura/daemon.rs
+ pub async fn run<H: EventHandler>(conf: TxIndexerConfig<H>) -> Result<TxIndexer, Error> {
+ let span = span!(Level::INFO, "Run TxIndexer");
+ let _enter = span.enter();
+
+ let chain = conf.network.to_chain_info()?;
+
+ let progress_tracker = match conf.since_slot {
+ Some((since_slot, _)) => Some(ProgressTracker::new(since_slot, &chain)?),
+ None => None,
+ };
+
+ let utils = Arc::new(Utils::new(chain));
+
+ let (source_handle, source_rx) = match conf.node_address {
+ NodeAddress::UnixSocket(path) => {
+ span!(Level::INFO, "BootstrapSourceViaSocket", socket_path = path).in_scope(|| {
+ WithUtils::new(
+ n2c_config(
+ AddressArg(BearerKind::Unix, path),
+ conf.network.to_magic_arg(),
+ conf.since_slot.clone(),
+ conf.safe_block_depth,
+ ),
+ utils.clone(),
+ )
+ .bootstrap()
+ })
+ }
+ NodeAddress::TcpAddress(hostname, port) => {
+ span!(Level::INFO, "BootstrapSourceViaTcp", hostname, port).in_scope(|| {
+ WithUtils::new(
+ n2n_config(
+ AddressArg(BearerKind::Tcp, format!("{}:{}", hostname, port)),
+ conf.network.to_magic_arg(),
+ conf.since_slot.clone(),
+ conf.safe_block_depth,
+ ),
+ utils.clone(),
+ )
+ .bootstrap()
+ })
+ }
+ }?;
+
+ // Optionally create a filter handle (if filter was provided)
+ let (filter_handle, filter_rx) = conf
+ .event_filter
+ .to_selection_config()
+ .bootstrap(source_rx)?;
+
+ let sink_handle = span!(Level::INFO, "BootstrapSink").in_scope(|| {
+ Callback::new(conf.handler, conf.retry_policy, utils, progress_tracker)
+ .bootstrap(filter_rx)
+ })?;
+
+ Ok(TxIndexer {
+ source_handle,
+ filter_handle,
+ sink_handle,
+ })
+ }
+}
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +
use std::sync::{atomic::AtomicUsize, Arc};
+
+use anyhow::anyhow;
+use chrono::{DateTime, Duration, Utc};
+use oura::utils::ChainWellKnownInfo;
+use tx_bakery::chain_query::{EraParameters, EraSummary, EraTime};
+
+use crate::from_oura::OuraParseError;
+
+/// A progress tracker holds information about the chain info required to calculate
+/// POSIX time from slots
+#[derive(Clone, Debug)]
+pub struct ProgressTracker {
+ pub system_start: DateTime<Utc>,
+ pub era_summaries: Vec<EraSummary>,
+ pub since_slot: u64,
+ pub sync_progress: Arc<AtomicUsize>,
+}
+
+impl ProgressTracker {
+ pub fn new(since_slot: u64, chain_info: &ChainWellKnownInfo) -> Result<Self, anyhow::Error> {
+ let system_start = DateTime::from_timestamp(chain_info.byron_known_time as i64, 0).ok_or(
+ anyhow!("Unable to convert shelley_known_time to to DateTime"),
+ )?;
+
+ Ok(ProgressTracker {
+ system_start,
+ era_summaries: chain_info_to_era_summaries(&system_start, chain_info)?,
+ since_slot,
+ sync_progress: Arc::new(AtomicUsize::new(0)),
+ })
+ }
+
+ pub fn get_percentage(&self, slot: u64) -> Result<f32, OuraParseError> {
+ let current_time = Utc::now();
+ let current_slot =
+ tx_bakery::time::time_into_slot(&self.era_summaries, &self.system_start, current_time)
+ .map_err(OuraParseError::TimeConversionError)?;
+
+ let synced = slot - self.since_slot;
+ let to_be_synced = current_slot - self.since_slot;
+
+ Ok(synced as f32 * 100.0 / to_be_synced as f32)
+ }
+}
+
+/// Convert Oura chain info into Ogmios EraSummaries.
+/// Oura does not include all eras, only Byron and Shelley, all other eras are part of
+/// Shelley. This is good enough for time calculations.
+fn chain_info_to_era_summaries(
+ system_start_time: &DateTime<Utc>,
+ chain_info: &ChainWellKnownInfo,
+) -> Result<Vec<EraSummary>, anyhow::Error> {
+ let byron_start = EraTime {
+ time: Duration::zero(),
+ slot: 0,
+ epoch: 0,
+ };
+
+ let shelley_start = EraTime {
+ time: DateTime::from_timestamp(chain_info.shelley_known_time as i64, 0).ok_or(anyhow!(
+ "Unable to convert shelley_known_time to to DateTime"
+ ))? - system_start_time,
+ slot: chain_info.shelley_known_slot,
+ epoch: chain_info.shelley_known_slot / chain_info.byron_epoch_length as u64,
+ };
+
+ Ok(vec![
+ EraSummary {
+ start: byron_start,
+ end: Some(shelley_start.clone()),
+ parameters: EraParameters {
+ epoch_length: chain_info.byron_epoch_length as u64,
+ slot_length: chain_info.byron_slot_length as u64 * 1000,
+ safe_zone: Some(4320),
+ },
+ },
+ EraSummary {
+ start: shelley_start,
+ end: None,
+ parameters: EraParameters {
+ epoch_length: chain_info.shelley_epoch_length as u64,
+ slot_length: chain_info.shelley_slot_length as u64 * 1000,
+ safe_zone: Some(4320),
+ },
+ },
+ ])
+}
+
fn:
) to \
+ restrict the search to a given item kind.","Accepted kinds are: fn
, mod
, struct
, \
+ enum
, trait
, type
, macro
, \
+ and const
.","Search functions by type signature (e.g., vec -> usize
or \
+ -> vec
or String, enum:Cow -> bool
)","You can look for items with an exact name by putting double quotes around \
+ your request: \"string\"
","Look for functions that accept or return \
+ slices and \
+ arrays by writing \
+ square brackets (e.g., -> [u8]
or [] -> Option
)","Look for items inside another one by searching for a path: vec::Vec
",].map(x=>""+x+"
").join("");const div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="${value.replaceAll(" ", " ")}
`}else{error[index]=value}});output+=`pub struct ParseCurrencySymbol(pub CurrencySymbol);
0: CurrencySymbol
source
. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub fn n2c_config(
+ addr: AddressArg,
+ magic: MagicArg,
+ since_slot: Option<(u64, String)>,
+ safe_block_depth: usize
+) -> Config
pub fn n2n_config(
+ addr: AddressArg,
+ magic: MagicArg,
+ since_slot: Option<(u64, String)>,
+ safe_block_depth: usize
+) -> Config
pub enum NetworkConfig {
+ ConfigPath {
+ node_config_path: String,
+ magic: u64,
+ },
+ WellKnown(NetworkName),
+}
source
. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub enum NetworkName {
+ PREPROD,
+ PREVIEW,
+ MAINNET,
+}
Typed network magic restricted to specific networks fully supported by Oura.
+source
. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub enum NodeAddress {
+ UnixSocket(String),
+ TcpAddress(String, u16),
+}
Simple description on how to connect to a local or remote node. +Used to build Oura source config.
+Path to Unix node.socket
+Hostname and port number for TCP connection to remote node
+self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub use self::deprecation_usage::*;
pub struct NetworkNameParseErr;
source
. Read moreself
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct TxIndexerConfig<H: EventHandler> {
+ pub handler: H,
+ pub node_address: NodeAddress,
+ pub network: NetworkConfig,
+ pub since_slot: Option<(u64, String)>,
+ pub safe_block_depth: usize,
+ pub event_filter: Filter,
+ pub retry_policy: RetryPolicy,
+}
handler: H
§node_address: NodeAddress
§network: NetworkConfig
§since_slot: Option<(u64, String)>
Slot number and hash as hex string (optional). +If not provided, sync will begin from the tip of the chain.
+safe_block_depth: usize
Minimum depth a block has to be from the tip for it to be considered “confirmed” +See: https://oura.txpipe.io/v1/advanced/rollback_buffer
+event_filter: Filter
§retry_policy: RetryPolicy
Retry policy - how much to retry for each event callback failure
+This only takes effect on ErrorPolicy for a particular error is Retry
.
+Once retries are exhausted, the handler will error (same treatment as ErrorPolicy::Exit)
self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub enum DBTypeConversionError {
+ InvariantBroken(String),
+ BigIntConversion(TryFromBigIntError<BigInt>),
+ PlutusDataEncodingError(PlutusDataEncodingError),
+}
self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub enum PlutusDataEncodingError {
+ CSLConversionError(JsError),
+ TryFromPLAError(TryFromPLAError),
+ TryFromCSLError(TryFromCSLError),
+}
PlutusData
+self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct Address { /* private fields */ }
Address
+self
into buf
in the expected format for the database.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct AssetQuantity { /* private fields */ }
AssetQuantity
+source
. Read moreself
into buf
in the expected format for the database.self
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct ChainPointer { /* private fields */ }
ChainPointer
+source
. Read moreself
into buf
in the expected format for the database.self
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct Credential { /* private fields */ }
Credential
+source
. Read moreself
into buf
in the expected format for the database.self
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct CurrencySymbol(pub Vec<u8>);
CurrencySymbol
+0: Vec<u8>
source
. Read moreself
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct DatumHash(pub Vec<u8>);
DatumHash
+0: Vec<u8>
key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct Ed25519PubKeyHash(pub Vec<u8>);
Ed25519PubKeyHash
+0: Vec<u8>
source
. Read moreself
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct OutputDatum { /* private fields */ }
OutputDatum
+source
. Read moreself
into buf
in the expected format for the database.self
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct PlutusData(pub Value);
0: Value
source
. Read moreself
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct ScriptHash(pub Vec<u8>);
ScriptHash
+0: Vec<u8>
source
. Read moreself
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct Slot(pub i64);
Slot
+0: i64
self
and other
) and is used by the <=
+operator. Read morekey
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct StakingCredential { /* private fields */ }
StakingCredential
+source
. Read moreself
into buf
in the expected format for the database.self
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct TokenName(pub Vec<u8>);
TokenName
+0: Vec<u8>
key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct TransactionHash(pub Vec<u8>);
TransactionHash
+0: Vec<u8>
source
. Read moreself
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct TransactionInput { /* private fields */ }
TransactionInput
+source
. Read moreself
into buf
in the expected format for the database.self
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct TransactionOutput { /* private fields */ }
TransactionOutput
+source
. Read moreself
into buf
in the expected format for the database.self
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct TxInInfo { /* private fields */ }
TxInInfo
+self
into buf
in the expected format for the database.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct Value(pub Vec<AssetQuantity>);
Value
+0: Vec<AssetQuantity>
key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct SyncProgressTable {
+ pub block_slot: i64,
+ pub block_hash: Vec<u8>,
+}
block_slot: i64
§block_hash: Vec<u8>
Obtain the sync status of the DB
+Save a new entity to the database.
+source
. Read moreself
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub enum ErrorPolicy<E> {
+ Retry,
+ Skip,
+ Exit,
+ Call(fn(_: E)),
+}
Specify what the indexer event handler should do for specific errors. See: ErrorPolicyProvider
.
+The idea is that an error type, E
, implements ErrorPolicyProvider
.
+Based on the different variants of E
, different ErrorPolicy
can be returned, which influences
+the behavior of the event handler.
Indicate the callback operation should be retried. Also see: RetryPolicy
.
Indicate that the error should be ignored, go to next event.
+Indicate that the event handler should exit with error.
+Indicate that the event handler should call given error handling function with the error.
+self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read moreErrorPolicyProvider
.
+The idea is that an error type, E
, implements ErrorPolicyProvider
.
+Based on the different variants of E
, different ErrorPolicy
can be returned, which influences
+the behavior of the event handler.ErrorPolicy
assignments.pub trait ErrorPolicyProviderwhere
+ Self: Sized,{
+ // Required method
+ fn get_error_policy(&self) -> ErrorPolicy<Self>;
+}
Trait that can be implemented for custom error types.
+Different variants in said error types can then be given different ErrorPolicy
assignments.
pub struct Filter {
+ pub curr_symbols: Vec<CurrencySymbol>,
+}
Interesting transaction components to look for when filtering transactions +relevant to the protocol. +Set curr_symbols to empty vectors to handle any transaction event indiscriminately.
+curr_symbols: Vec<CurrencySymbol>
self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub enum Events {
+ EventHandlerFailure,
+}
self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub trait EventHandler{
+ type Error: Error + ErrorPolicyProvider;
+
+ // Required method
+ fn handle(
+ &self,
+ event: ChainEvent
+ ) -> impl Future<Output = Result<(), Self::Error>>;
+}
pub enum ChainEvent {
+ TransactionEvent {
+ time: ChainEventTime,
+ transaction: TransactionEventRecord,
+ },
+ RollbackEvent {
+ block_slot: u64,
+ block_hash: String,
+ },
+ SyncProgressEvent {
+ block_slot: u64,
+ block_hash: String,
+ percentage: f32,
+ },
+}
Chain events that the indexer is configured to produce.
+A filtered transaction was confirmed
+Rollback event occurred
+Chain syncronisation progressed
+source
. Read moreself
and other
values to be equal, and is used
+by ==
.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub fn parse_oura_event(
+ ev: Event,
+ progress_tracker: &mut Option<ProgressTracker>
+) -> Result<Option<ChainEvent>, OuraParseError>
pub struct ChainEventTime {
+ pub block_number: u64,
+ pub block_hash: String,
+ pub slot: u64,
+}
Indication of when an event happened in the context of the chain.
+block_number: u64
§block_hash: String
§slot: u64
source
. Read moreself
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct TransactionEventRecord {
+ pub hash: TransactionHash,
+ pub fee: u64,
+ pub size: u32,
+ pub inputs: Vec<TransactionInput>,
+ pub outputs: Vec<TxInInfo>,
+ pub mint: Value,
+ pub plutus_data: HashMap<DatumHash, Datum>,
+}
Details on an transaction event (excluding unnecessary information).
+hash: TransactionHash
§fee: u64
§size: u32
§inputs: Vec<TransactionInput>
§outputs: Vec<TxInInfo>
§mint: Value
§plutus_data: HashMap<DatumHash, Datum>
source
. Read moreself
and other
values to be equal, and is used
+by ==
.key
and return true
if they are equal.self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read moreErrorPolicy::Retry
pub struct RetryPolicy {
+ pub max_retries: u32,
+ pub backoff_unit: Duration,
+ pub backoff_factor: u32,
+ pub max_backoff: Duration,
+}
Influence retrying behavior.
+i.e How many times and how often a failed operation should be retried.
+Given we are dealing with ErrorPolicy::Retry
max_retries: u32
§backoff_unit: Duration
§backoff_factor: u32
§max_backoff: Duration
source
. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read moreRedirecting to ../../tx_indexer/struct.TxIndexer.html...
+ + + \ No newline at end of file diff --git a/artifacts/tx-indexer/tx_indexer/progress_tracker/index.html b/artifacts/tx-indexer/tx_indexer/progress_tracker/index.html new file mode 100644 index 0000000..9cd8b5f --- /dev/null +++ b/artifacts/tx-indexer/tx_indexer/progress_tracker/index.html @@ -0,0 +1,3 @@ +pub struct ProgressTracker {
+ pub system_start: DateTime<Utc>,
+ pub era_summaries: Vec<EraSummary>,
+ pub since_slot: u64,
+ pub sync_progress: Arc<AtomicUsize>,
+}
A progress tracker holds information about the chain info required to calculate +POSIX time from slots
+system_start: DateTime<Utc>
§era_summaries: Vec<EraSummary>
§since_slot: u64
§sync_progress: Arc<AtomicUsize>
source
. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read morepub struct TxIndexer {
+ pub source_handle: JoinHandle<()>,
+ pub filter_handle: JoinHandle<()>,
+ pub sink_handle: JoinHandle<()>,
+}
source_handle: JoinHandle<()>
§filter_handle: JoinHandle<()>
§sink_handle: JoinHandle<()>
self
into a Left
variant of Either<Self, Self>
+if into_left
is true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreself
into a Left
variant of Either<Self, Self>
+if into_left(&self)
returns true
.
+Converts self
into a Right
variant of Either<Self, Self>
+otherwise. Read moreSubscriber
to this type, returning a
+[WithDispatch
] wrapper. Read more