From 4639f479056cc31fa65e141037cc739d085b9397 Mon Sep 17 00:00:00 2001 From: Fabrizio Romano Genovese Date: Fri, 5 Jan 2024 14:04:52 +0100 Subject: [PATCH 1/7] Added post. --- ...24-01-05-correctly-pricing-txs-parallel.md | 105 ++++++++ .../Boxes.png | Bin 0 -> 2110 bytes .../BoxesMerged.png | Bin 0 -> 1849 bytes .../BoxesMonoidal.png | Bin 0 -> 3307 bytes .../EckmannHilton.png | Bin 0 -> 4044 bytes .../PetriConflict.png | Bin 0 -> 32665 bytes .../PetriNetExecution.png | Bin 0 -> 27927 bytes .../tex/Boxes.tex | 158 ++++++++++++ .../tex/BoxesMerged.tex | 156 ++++++++++++ .../tex/BoxesMonoidal.tex | 163 ++++++++++++ .../tex/EckmannHilton.tex | 182 ++++++++++++++ .../tex/PetriConflict.tex | 238 ++++++++++++++++++ .../tex/PetriNetExecution.tex | 224 +++++++++++++++++ 13 files changed, 1226 insertions(+) create mode 100644 _posts/2024-01-05-correctly-pricing-txs-parallel.md create mode 100644 assetsPosts/2024-01-05-correctly-pricing-txs-parallel/Boxes.png create mode 100644 assetsPosts/2024-01-05-correctly-pricing-txs-parallel/BoxesMerged.png create mode 100644 assetsPosts/2024-01-05-correctly-pricing-txs-parallel/BoxesMonoidal.png create mode 100644 assetsPosts/2024-01-05-correctly-pricing-txs-parallel/EckmannHilton.png create mode 100644 assetsPosts/2024-01-05-correctly-pricing-txs-parallel/PetriConflict.png create mode 100644 assetsPosts/2024-01-05-correctly-pricing-txs-parallel/PetriNetExecution.png create mode 100644 assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/Boxes.tex create mode 100644 assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/BoxesMerged.tex create mode 100644 assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/BoxesMonoidal.tex create mode 100644 assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/EckmannHilton.tex create mode 100644 assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/PetriConflict.tex create mode 100644 assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/PetriNetExecution.tex diff --git a/_posts/2024-01-05-correctly-pricing-txs-parallel.md b/_posts/2024-01-05-correctly-pricing-txs-parallel.md new file mode 100644 index 0000000..4ffd959 --- /dev/null +++ b/_posts/2024-01-05-correctly-pricing-txs-parallel.md @@ -0,0 +1,105 @@ +--- +layout: post +title: Correctly pricing blockspace in a causally parallel world +author: Fabrizio Genovese, Daniele Palombi +categories: [parallelization, causality, MEV, EVM, Jito] +excerpt: Where we investigate the thread that ties Jito, the parallel EVM, auction theory and physics together. +image: assetsPosts/2023-07-26-lagrangian-intent-search-i/greedyAction.png +usemathjax: true +thanks: +--- + +First of all, happy new year! We hope you had a blast as much as we did in 2023, and that you're all set to double down on 2024. + +There seems to be a couple of new trends in the Ethereum Twitter echo chamber these days: +- The discovery that there's MEV on Solana, and they ain't fucking around with it; +- The fact that a lot of projects are working on parallelizing the Ethereum Virtual Machine (EVM), and this seems to be 'the thing' in Ethereum now. + +Clearly we can't miss the party, and as usual we'll try to wrtite about interesting stuff at the intersection of these topics. For starters, the natural question that we asked ourselves is: + +> how do you price blockspace in a parallelized world? + + +## What is a parallelized world? + +Parallel execution, in layman terms, means that you can split a given computation between different threads that happen at the same time. Thus, if you have a multi-core architecture, you can use more than one core at the same time to perform the computation. The advantage is tangible, especially given how in the last decade or so multi-core architectures have become increasingly common. +Clearly, there are some tasks that are highly parallelizable - e.g. bruteforcing a password - and some tasks that aren't - for instance computing Verifiable Delay Functions (VDFs). + +## A story of inclusion + +Now, our idea is very simple. Parallelization is good because it makes execution faster. As such, one would like to incentivize blocks that are 'as parallel as possible'. Furthermore, we must pair the computation layer with the economic layer, and the way we do it is via *transaction fees*: We put a cost on each transaction that should be proportional to how much (space, computational) resources the transaction consumes, and to how badly the user wants that transaction to be included in a block. + +Naïvely, we'd like 'highly parallelizable' transactions to be cheaper as the amount of computation one must do is more efficient. Paradoxically, this is easier said than done, and depends on the fact that fees represent costs for some actors, but revenues for others. If we were to make 'highly parallel transactions' fees cheaper - e.g. by multiplying the transaction gas size by a 'parallelization coefficient' ranging from 0 to 1 - we would incentivize one end of the pipeline (end users, dapp developers) to push for highly parallel blocks. At the same time, we would incentivate the other end of the pipeline (the fee recipitents, so validators, builders, etc) to reject highly parallel blocks in favor of sequential ones, just because they pay better. + +This has the very counterintuitive effect that if a user really wants a transaction to be included, they could stand a better chance by just opting for a highly sequential implementation of whatever they want to do (e.g. using a bad, gas guzzling unparallelized dapp instead of a nice one). + +## A story of ordering + +In the most ideal setting described above, transaction fees are taken to represent *inclusion preferences*. That is, you pay more depending on how badly you want to be included in a block. Unfortunately, we all know very well how the picture is much more complicated than this, as transaction fees have been (and are) used, especially in Ethereum, to represent *ordering preferences*, that is, how badly you want your transaction to be close to the top of the block it is in. + +This observation is what ties together parallel computation and MEV. Imagine that there are two transactions that compete for being top of the block. Assume furthermore that there is no overlap whatsoever between the state read and written by them. Are the transactions 'really' competing? The answer is no, because the way you order them does not matter: By definition, whatever one transaction does won't influence what the other does, and hence it doesn't matter who ends up being on top. + +This is precisely what happens in Jito, where 'transactions that do not stomp on each other's feet' are put into different auctions running in parallel. This difference was highlighted in a very approachable way in [Tarun's twitter thread](https://warpcast.com/pinged/0xa6d3fe25). + +In a way, this tells us that there are MEV auctions out there that already take parallelization into account. On the surface this shouldn't surprise, as Solana's execution layer is already parallelized. Yet, do not let yourself be fooled by this. Indeed: + +> You do not need parallelized execution layers to run parallelized MEV auctions. + +## The knot that ties all together + +So, on one hand we have parallelized execution layers, and on the other we have 'parallelized economic layers', if you wish. What connects these two concepts is called *causality*, and it is a very, very hot topic in some research areas at the moment (mainly quantum gravity and other complicated stuff, but I won't dwelve into it). The whole spiel of causality is understanding and describing what does it mean for different events to be related. You can see how in a world where the notion of time changes with respect to the observer (a bit like in distributed systems), or where you can instantly teleport things around, saying 'this event came before this one' becomes meaningless. Instead, we want to characterize the notion of 'causation' in a way that is completely independent from the notion of 'time'. If you like physics, a good, technical read about this is [here](https://arxiv.org/abs/2206.08911). + +Tarun is definitely on the right track when he points out in his thread that transactions in a Jito auction form a Directed Acyclic Graph (DAG). That's one way to see it, but we have more powerful tools in our toolbox that we can use. + +A world where only sequential composition is possible is mathematically called *category*. This is a term you read multiple times on this blog, but in a nutshell it means that you have processes changing state, represented as boxes: + +![Some processes and states.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/Boxes.png) + +And that processes can be piped together in the obvious way (here $g$ acts on the state changed by $f$): + +![Process composition.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/BoxesMerged.png) + +From a very high-level perspective, categories are generated by graphs, which are the underlying topologies of *finite state machines*. Indeed, as you will probably know, a finite state machine has just one monolithic state, which you operate on sequentially. +Here causality is really boring, as 'there is not much to do', and the ordering between transactions is fully established. Things become much more interesting when we add another dimension, obtaining what is called a *monoidal category*. Here state can be split in multiple components - represented as different wires - and processes can act on different wires at the same time: + +![Monoidal processes and states.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/BoxesMonoidal.png) + +One of the main tenets of monoidal categories is the [Eckmann-Hilton argument](https://en.wikipedia.org/wiki/Eckmann%E2%80%93Hilton_argument), which essentially says that 'two processes modifying non overlapping threads have no causal relation'. Graphically, this means we can slide these processes past to each other: + +![Eckmann-Hilton.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/EckmannHilton.png) + + +Monoidal categories in their most general form are generated by *hypergraphs*, which - [modulo some very deep but boring caveats](https://arxiv.org/abs/2101.04238) - are the underlying topologies of [Petri nets](https://core.ac.uk/download/pdf/82342688.pdf), a very famous model of concurrent systems. + +An example of how a parallel computation in a Petri net is expressed in terms of monoidal categories can be seen below from the following picture from [a paper of ours](https://arxiv.org/abs/2101.09100): + +![image description](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/PetriNetExecution.png) + +As you can see, in the net you can fire $t$ and $u$ independently, and indeed the corresponding $t$ and $u$ processes in the 'string diagram' can be slid one past the other. On the other hand, you can decide if you want $v$ to use the state that was already in $p_2$ or if you want it to use the one generated by $t$ (as we do above). The two choices originate different causal structures (different DAGs in Tarun's language) and generate different diagrams that cannot be homotopically deformed one into the other. + +### And so parallel computation and parallel auctions can be independent + +Going back to our point, causality is what enables parallelization **both** at the computational and economic layer: Causally independent transactions - as $t$ and $u$ above - can be executed on different cores. Similarly, they do not compete for ordering in a block, and can be put into different auctions. +But you see, these two facts are **not** mutually related: Their are both caused by having causally-independent transactions (yes, pun intended and yes, this is higher-level causality!). + +Indeed, in the (currently) non-parallel EVM we could definitely split the block not only horizontally - as in the top of the block/bottom of the block paradigm - but also vertically, allowing for multiple transactions to be top of the block and by running multiple auctions in parallel. Granted, this split only exists at 'MEV time' and the block will be fully sequentialized at 'executon time', but then again this does not matter because of the Eckmann-Hilton argument before: You can sequentialize in any ordering you want! + +Obvously, in a world where: +- There are mempools, and +- Execution is parallel + +Stitching the (parallel) execution and the (parallel) MEV/auction layer together becomes more important, because obviously you'd like incentives to be aligned. You don't want block builders to cherry pick transactions in a way that reduces the usage of computational parallelism, do you? +...It goes without saying that if you're working on parallelizing the EVM and you never thought about the corresponding MEV/gas pricing mechanisms our phone lines are open! + +### Welcome to the Jungle + +The causality story runs really deep and there are much more complex forms of causality that we already have the tools to investigate. Interesting, the parallel 'maths - physics - models of computation - economics' keeps holding. Just to give an example, in Physics you have **teleportation**, where processes can go 'from the future to the past', yanking the causal flow of things. The computational analogue, which is probably a bit easier to grasp, is an extension of Petri nets where you can do state borrowing and error correction. In the picture below, again taken from +[a paper of ours](https://arxiv.org/abs/1805.05988), the transition $\nu$ needs a state that hasn't been created yet. To proceed, it creates this state together with a 'debt' (represented by the red token). Now $\nu$ and $\tau$ can be computed in parallel. The consistency of the whole system is restored when $\mu$ is fired, providing the state $\nu$ requested and 'annihilating' the debt (yes, 'annihilation' as in particle-antiparticle annihilation is not a coincidence here). + +![image description](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/PetriConflict.png) + +By 'yanking' the diagram, one can see that the causal flow of this computation is equivalent to firing $\tau$, then $\mu$, then $\nu$. These advanced forms of causality may be useful in intentland, where maybe we want to solve different intents 'in parallel' and then stitch them together afterwards. + +So should you hear about 'self-healing' or 'error correcting' parallel EVM in the future, let it be know that we squatted these terms first! :P + +Ok, we hope we weren't too late to the party. Stay tuned for more updates! \ No newline at end of file diff --git a/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/Boxes.png b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/Boxes.png new file mode 100644 index 0000000000000000000000000000000000000000..74de99c386f1077e976add5b5b5fb74e62afe26a GIT binary patch literal 2110 zcmZ{lc|6qn8pnS#2J^ENA&D$g_QRR6jxmOqjgYk{YGQ_pVPr%dYSeU%;bxf;!cnBq zN%ldLNS4M{+Kpt*)?(BZx+iDO{o~%({i8p=&*yo*&+Gkq{`-8=eY{D^3Of}508n-( z5|99}NC5y$0RU(+iraj# z(gieZ9|;d^rezI0kWL_j92_rI@_!!jaTHG4$TQu&2=em~Sw*Crobr`L0Fe9Sj^7)Q zH2SgRL5!HJlJ>wML>nSBFX6r_7RkuW$lr(cGf+j3`jF9~>H2zZm$JCGEW1F>isfWK zVo!6JLOo1#8yDNrK$L0+Thpj6Dt&g61!F&%d3_9IWq19X(BEt*@?fvkE;YhD%SGjM z@iwt->UKtAy2F5hqkojf90=((r1ZEhchWUj<{xG zJC`Vyi_YS2#Ttj-f+>MmmD z+Hf2QtgQN3-|F?;!TNKRw}^7_6eVkS+-)faImWv&!h%?8Oqg8v#hO4(#RRlrPwKhj zw|&Yw0T=kULxta2yu|K}Gg#PFYvpA>KY=+k6j~;mckc!|?Wj9!Plq)M6jVOJl zVZ?e}GZWksq%yR(eSv2l9fz*1DMkGzTMA>@zvb1qMV}{KwP>jBrDK}C24yLBSDJId zXp`za9g+1(S7^bWPG-=l>HUFcA5M*b=QYhK{g@oK-E7Ft<4v)vis}zmE!Iov*H~6|Y zyNFigkB;ziR{Zlk5@(mgF79v9$*6B$s9U(>sMqwka&*ob_1&e1RP%;Npp^SIA!8mz zhP~Xig`6fCGd1tb6d&}ku}9kD+G)_nm%d;9d@xzglAKrAX$J$8Tkk8l`jbiK;8oTd z>^?WVlS}329sVT8-IZBIvETtBMQ{b8St$#LXZ6q|tzf&FI7)an9s+5L=yb+mE&} z=Lh+NX2dsG-BS)DUE)gJ{H%srqJB9&FNDn$fD-?gx&cJk5ZU2o=Zk=Q8nbhi`{LWUjXGJa`tP+( z4~`xP@ckW6!0XGno^GY)r${}*qpGrxK`G^Hd-t8p?JyO+ujIges`LxCADm^@kDzSxHkej+6O+oaGp#KFqv9VQ5=|dKts?-_ z*e{NEcvSqE0pr!8n)Et4tJmZ+MYu#IUDIwKpEZ^5c{9Ey!cIw?-XVWw))SIM%a;4& zt_@Zvr~=Y3ITu+DlFT49SLjg5I}_u{zIGVe0LlycIHSV28m4R zydv{|06ms^BI3-?0i|Ngzcbk6zZaM%=(Kp|F*@Vt%;EH{6e*+jH^ZPtU=Gku#h-|c b0etX83zVg;zulou=^Ah+c;jnaDHr|%zuTI{ literal 0 HcmV?d00001 diff --git a/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/BoxesMerged.png b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/BoxesMerged.png new file mode 100644 index 0000000000000000000000000000000000000000..e4682c7217e2d4bb683fc4062fd81d782307e84f GIT binary patch literal 1849 zcmZ{lc{JOJ7RP_6Xep{%yD~$%2$i6!kFsZ646py%(R-(h;?GCbT9@l^Zt0}yg&NKz2Cc>&$;LRanDV+v$d2IR}u#RKoW~V zIRJnVP7osw9}@VhqU#j`QTM|**Z@HMX#luI1%ST=rCW;t5Ca8(Wp4n07XpBML`l0n zLeLQQwYEe72X`O5do9S0L}1*a1&aBvp$9`v1c4YCYhxj{C?qOjpimedo(TY=OIXwu z$GDFxC9g@J&?g2=UC2L+LRIt9gKmd}DKZWKq`ZteDaB9>^Uy7MOJR(6J^Nyv-pu0{ z+tPh$+4dkpsQ5rJ@Ockz=Kyw^kj~(jGImvFuKlvO#b{u682^!gnUK~7F*98+uGUsB zlS;+rOzM;qwI@$sUCj*Ch+rin<$9N-PEgaDoUq!USBS^*4{pBNXsm| zExn7!a2DTx87w?eeVkX?n1 zQwzS4+WCN;U52nH4qXg6=!}SX(%aV0IaGk=TO_VomkJpe$eqbGdhoRnqB8mNYD-Yc%Nr&jv*4((-kA?3xHl#V;@9VjaWg2E$ zD6yY5vj)HeDv{dXvfdur zDZg&#m0834XM1}WA@?k(#RJ3ez_{_|E>u{@-4$BGBYd`>j0VmJoJAjLYCUP(PHB7Coy#kIQf5P(C27P5c3caH=JWLA zHV+g%8e25)YV!JJV_dBYv|qXWwF1u#uzs$jwoxM!WAV2YNPk4P_J$kb9L`6UQ90;o zpm?6K0T{}d+EZhUyT#a>%9e0>q&jZgGl#@bgef?Ih?9yHc2P2ceF24VnvzPZCwI zgG04Oi3F8VR@HM46}_3fpf5ANUx-tOk+B0gi5bU`%G*>AJ)PO0Al>1^iZd%smSxHm zFHW>=`lvRYTlC|J+RNeM>B#uF=`Z?Pm%q42GSU&|-OrekP9gM6SS8w)mLOSfdH%2j zjh|s=%f;3+110fMv}wtmzV9Bbf(GtR|G#&QZb68oN%bg_eZQiT_v)KW>2pi(O@eF~ zs+#l(FW;lFRQl)N(_XD(RSAq2)rtS`ENCAOB0Vji$;Z#)bhO(MbA?jW&Uxo=rD@=j zzm7^S@)GK5syYUq^~><{r*dLSW58WF^I{@|rs%zKiN61H2!*+qgB$-XslDCuL)JcP zNhJ3YyG?c&4=n~|z;q2y(vdCpaX^J zKrcALVDJlia6JPE6bgqzlcq+z{tqCMt_KHDz7I%e#Bv0{+5b%-2NV6H$v(u0?=!CD s&PV|x`!5r5Jpk_P9~B);3J2^^XdT%33wT39kDv`;Eo@QsX5PvF0aCF^@&Et; literal 0 HcmV?d00001 diff --git a/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/BoxesMonoidal.png b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/BoxesMonoidal.png new file mode 100644 index 0000000000000000000000000000000000000000..39fd5b33b6046415e98db6bfc6d5050ad377cb7b GIT binary patch literal 3307 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 JE;A>_{U5AE`TPI? literal 0 HcmV?d00001 diff --git a/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/EckmannHilton.png b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/EckmannHilton.png new file mode 100644 index 0000000000000000000000000000000000000000..175a6d37446f4bc0972ee86aaf74530e04251c26 GIT binary patch literal 4044 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 E3lUY2T>t<8 literal 0 HcmV?d00001 diff --git a/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/PetriConflict.png b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/PetriConflict.png new file mode 100644 index 0000000000000000000000000000000000000000..598f8096c3fc0865d4eacdbf2272980011560aba GIT binary patch literal 32665 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

W1-w80Edz=Z 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 MT~7^j?&_WY0}Z_&$p8QV literal 0 HcmV?d00001 diff --git a/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/Boxes.tex b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/Boxes.tex new file mode 100644 index 0000000..3bb541a --- /dev/null +++ b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/Boxes.tex @@ -0,0 +1,158 @@ + +\documentclass{standalone} +\usepackage{tikz} +\usepackage{amsfonts} + + % + \usepackage{tikz} % + \usetikzlibrary{ + petri, % + backgrounds, % + arrows, % + positioning, % + decorations.markings, % + calc, % + fit, % + } +\tikzstyle{inarrow}=[->, >=stealth, shorten >=.03cm,line width=0.5] +\tikzstyle{outarrow}=[<-, >=stealth, shorten <=.03cm,line width=1.5] + + + + + % + \tikzset{ % + oriented WD/.style={% + every to/.style={ + out=0,in=180,draw + }, + label/.style={ + font=\everymath\expandafter{\the\everymath\scriptstyle}, + inner sep=0pt, + node distance=2pt and -2pt + }, + semithick, + node distance=1 and 1, + decoration={ + markings, mark=at position \stringdecpos with \stringdec + }, + ar/.style={ + postaction={decorate} + }, + execute at begin picture={ + \tikzset{ + x=\bbx, y=\bby, + every fit/.style={ + inner xsep=\bbx, inner ysep=\bby + } + } + } + }, + string decoration/.store in=\stringdec, + string decoration={ + \arrow{stealth}; + }, + string decoration pos/.store in=\stringdecpos, + string decoration pos=.7, + bbx/.store in=\bbx, + bbx = 1.5cm, + bby/.store in=\bby, + bby = 1.5ex, + bb port sep/.store in=\bbportsep, + bb port sep=1.5, + bb port length/.store in=\bbportlen, + bb port length=4pt, + bb penetrate/.store in=\bbpenetrate, + bb penetrate=0, + bb min width/.store in=\bbminwidth, + bb min width=1cm, + bb rounded corners/.store in=\bbcorners, + bb rounded corners=2pt, + bb small/.style={ + bb port sep=1, + bb port length=2.5pt, + bbx=.4cm, bb min width=.4cm, + bby=.7ex + }, + bb medium/.style={ + bb port sep=1, + bb port length=2.5pt, + bbx=.4cm, + bb min width=.4cm, + bby=.9ex + }, + bb/.code 2 args={% + \pgfmathsetlengthmacro{\bbheight}{\bbportsep * (max(#1,#2)+1) * \bby} + \pgfkeysalso{ + draw, + minimum height=\bbheight, + minimum width=\bbminwidth, + outer sep=0pt, + rounded corners=\bbcorners, + thick, + prefix after command={ + \pgfextra{\let\fixname\tikzlastnode} + }, + append after command={ + \pgfextra{ + \draw + \ifnum #1=0 + {} + \else + foreach \i in {1,...,#1} { + ($(\fixname.north west)!{\i/(#1+1)}!(\fixname.south west)$) +(- + \bbportlen,0) + coordinate (\fixname_in\i) -- +(\bbpenetrate,0) coordinate (\fixname_in\i') + } + \fi + % + \ifnum + #2=0{} + \else + foreach \i in {1,...,#2} { + ($(\fixname.north east)!{\i/(#2+1)}!(\fixname.south east)$) +(- + \bbpenetrate,0) + coordinate (\fixname_out\i') -- +(\bbportlen,0) coordinate (\fixname_out\i) + } + \fi; + } + } + } + }, + bb name/.style={ + append after command={ + \pgfextra{ + \node[anchor=north] at (\fixname.north) {#1} + ;} + } + } + } + + \begin{document} + +\scalebox{3}{ +\begin{tikzpicture}[oriented WD, bb port length=10pt] + % + \node[bb={1}{1}, fill={black!20}] (X1) {$f$}; + % + % + \draw[label] + node [left=2pt of X1_in1] {$A$} + node [right=2pt of X1_out1] {$B$} + ; + % + \begin{scope}[xshift=10em] + \node[bb={1}{1}, fill={black!20}] (X2) {$g$}; + % + % + \draw[label] + node [left=2pt of X2_in1] {$B$} + node [right=2pt of X2_out1] {$C$} + ; + \end{scope} + +\end{tikzpicture} +}{} + + +\end{document} \ No newline at end of file diff --git a/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/BoxesMerged.tex b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/BoxesMerged.tex new file mode 100644 index 0000000..dfe3e74 --- /dev/null +++ b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/BoxesMerged.tex @@ -0,0 +1,156 @@ + +\documentclass{standalone} +\usepackage{tikz} +\usepackage{amsfonts} + + % + \usepackage{tikz} % + \usetikzlibrary{ + petri, % + backgrounds, % + arrows, % + positioning, % + decorations.markings, % + calc, % + fit, % + } +\tikzstyle{inarrow}=[->, >=stealth, shorten >=.03cm,line width=0.5] +\tikzstyle{outarrow}=[<-, >=stealth, shorten <=.03cm,line width=1.5] + + + + + % + \tikzset{ % + oriented WD/.style={% + every to/.style={ + out=0,in=180,draw + }, + label/.style={ + font=\everymath\expandafter{\the\everymath\scriptstyle}, + inner sep=0pt, + node distance=2pt and -2pt + }, + semithick, + node distance=1 and 1, + decoration={ + markings, mark=at position \stringdecpos with \stringdec + }, + ar/.style={ + postaction={decorate} + }, + execute at begin picture={ + \tikzset{ + x=\bbx, y=\bby, + every fit/.style={ + inner xsep=\bbx, inner ysep=\bby + } + } + } + }, + string decoration/.store in=\stringdec, + string decoration={ + \arrow{stealth}; + }, + string decoration pos/.store in=\stringdecpos, + string decoration pos=.7, + bbx/.store in=\bbx, + bbx = 1.5cm, + bby/.store in=\bby, + bby = 1.5ex, + bb port sep/.store in=\bbportsep, + bb port sep=1.5, + bb port length/.store in=\bbportlen, + bb port length=4pt, + bb penetrate/.store in=\bbpenetrate, + bb penetrate=0, + bb min width/.store in=\bbminwidth, + bb min width=1cm, + bb rounded corners/.store in=\bbcorners, + bb rounded corners=2pt, + bb small/.style={ + bb port sep=1, + bb port length=2.5pt, + bbx=.4cm, bb min width=.4cm, + bby=.7ex + }, + bb medium/.style={ + bb port sep=1, + bb port length=2.5pt, + bbx=.4cm, + bb min width=.4cm, + bby=.9ex + }, + bb/.code 2 args={% + \pgfmathsetlengthmacro{\bbheight}{\bbportsep * (max(#1,#2)+1) * \bby} + \pgfkeysalso{ + draw, + minimum height=\bbheight, + minimum width=\bbminwidth, + outer sep=0pt, + rounded corners=\bbcorners, + thick, + prefix after command={ + \pgfextra{\let\fixname\tikzlastnode} + }, + append after command={ + \pgfextra{ + \draw + \ifnum #1=0 + {} + \else + foreach \i in {1,...,#1} { + ($(\fixname.north west)!{\i/(#1+1)}!(\fixname.south west)$) +(- + \bbportlen,0) + coordinate (\fixname_in\i) -- +(\bbpenetrate,0) coordinate (\fixname_in\i') + } + \fi + % + \ifnum + #2=0{} + \else + foreach \i in {1,...,#2} { + ($(\fixname.north east)!{\i/(#2+1)}!(\fixname.south east)$) +(- + \bbpenetrate,0) + coordinate (\fixname_out\i') -- +(\bbportlen,0) coordinate (\fixname_out\i) + } + \fi; + } + } + } + }, + bb name/.style={ + append after command={ + \pgfextra{ + \node[anchor=north] at (\fixname.north) {#1} + ;} + } + } + } + + \begin{document} + +\scalebox{3}{ +\begin{tikzpicture}[oriented WD, bb port length=10pt] + % + \node[bb={1}{1}, fill={black!20}] (X1) {$f$}; + % + % + \draw[label] + node [left=2pt of X1_in1] {$A$} + ; + % + \begin{scope}[xshift=4em] + \node[bb={1}{1}, fill={black!20}] (X2) {$g$}; + % + % + \draw[label] + node [right=2pt of X2_out1] {$C$} + ; + \end{scope} + +\end{tikzpicture} +}{} + + +\end{document} \ No newline at end of file diff --git a/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/BoxesMonoidal.tex b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/BoxesMonoidal.tex new file mode 100644 index 0000000..8308a0f --- /dev/null +++ b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/BoxesMonoidal.tex @@ -0,0 +1,163 @@ + +\documentclass{standalone} +\usepackage{tikz} +\usepackage{amsfonts} + + % + \usepackage{tikz} % + \usetikzlibrary{ + petri, % + backgrounds, % + arrows, % + positioning, % + decorations.markings, % + calc, % + fit, % + } +\tikzstyle{inarrow}=[->, >=stealth, shorten >=.03cm,line width=0.5] +\tikzstyle{outarrow}=[<-, >=stealth, shorten <=.03cm,line width=1.5] + + + + + % + \tikzset{ % + oriented WD/.style={% + every to/.style={ + out=0,in=180,draw + }, + label/.style={ + font=\everymath\expandafter{\the\everymath\scriptstyle}, + inner sep=0pt, + node distance=2pt and -2pt + }, + semithick, + node distance=1 and 1, + decoration={ + markings, mark=at position \stringdecpos with \stringdec + }, + ar/.style={ + postaction={decorate} + }, + execute at begin picture={ + \tikzset{ + x=\bbx, y=\bby, + every fit/.style={ + inner xsep=\bbx, inner ysep=\bby + } + } + } + }, + string decoration/.store in=\stringdec, + string decoration={ + \arrow{stealth}; + }, + string decoration pos/.store in=\stringdecpos, + string decoration pos=.7, + bbx/.store in=\bbx, + bbx = 1.5cm, + bby/.store in=\bby, + bby = 1.5ex, + bb port sep/.store in=\bbportsep, + bb port sep=1.5, + bb port length/.store in=\bbportlen, + bb port length=4pt, + bb penetrate/.store in=\bbpenetrate, + bb penetrate=0, + bb min width/.store in=\bbminwidth, + bb min width=1cm, + bb rounded corners/.store in=\bbcorners, + bb rounded corners=2pt, + bb small/.style={ + bb port sep=1, + bb port length=2.5pt, + bbx=.4cm, bb min width=.4cm, + bby=.7ex + }, + bb medium/.style={ + bb port sep=1, + bb port length=2.5pt, + bbx=.4cm, + bb min width=.4cm, + bby=.9ex + }, + bb/.code 2 args={% + \pgfmathsetlengthmacro{\bbheight}{\bbportsep * (max(#1,#2)+1) * \bby} + \pgfkeysalso{ + draw, + minimum height=\bbheight, + minimum width=\bbminwidth, + outer sep=0pt, + rounded corners=\bbcorners, + thick, + prefix after command={ + \pgfextra{\let\fixname\tikzlastnode} + }, + append after command={ + \pgfextra{ + \draw + \ifnum #1=0 + {} + \else + foreach \i in {1,...,#1} { + ($(\fixname.north west)!{\i/(#1+1)}!(\fixname.south west)$) +(- + \bbportlen,0) + coordinate (\fixname_in\i) -- +(\bbpenetrate,0) coordinate (\fixname_in\i') + } + \fi + % + \ifnum + #2=0{} + \else + foreach \i in {1,...,#2} { + ($(\fixname.north east)!{\i/(#2+1)}!(\fixname.south east)$) +(- + \bbpenetrate,0) + coordinate (\fixname_out\i') -- +(\bbportlen,0) coordinate (\fixname_out\i) + } + \fi; + } + } + } + }, + bb name/.style={ + append after command={ + \pgfextra{ + \node[anchor=north] at (\fixname.north) {#1} + ;} + } + } + } + + \begin{document} + +\scalebox{3}{ +\begin{tikzpicture}[oriented WD, bb port length=10pt] + % + \node[bb={2}{1}, fill={black!20}] (X1) {$f$}; + % + % + \draw[label] + node [left=2pt of X1_in1] {$A_1$} + node [left=2pt of X1_in2] {$A_2$} + node [right=2pt of X1_out1] {$B$} + ; + % + \begin{scope}[xshift=10em] + \node[bb={3}{2}, fill={black!20}] (X2) {$g$}; + % + % + \draw[label] + node [left=2pt of X2_in1] {$B_1$} + node [left=2pt of X2_in2] {$B_2$} + node [left=2pt of X2_in3] {$B_3$} + + node [right=2pt of X2_out1] {$C_1$} + node [right=2pt of X2_out2] {$C_2$} + ; + \end{scope} + +\end{tikzpicture} +}{} + + +\end{document} \ No newline at end of file diff --git a/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/EckmannHilton.tex b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/EckmannHilton.tex new file mode 100644 index 0000000..e3ad622 --- /dev/null +++ b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/EckmannHilton.tex @@ -0,0 +1,182 @@ + +\documentclass{standalone} +\usepackage{tikz} +\usepackage{amsfonts} + + % + \usepackage{tikz} % + \usetikzlibrary{ + petri, % + backgrounds, % + arrows, % + positioning, % + decorations.markings, % + calc, % + fit, % + } +\tikzstyle{inarrow}=[->, >=stealth, shorten >=.03cm,line width=0.5] +\tikzstyle{outarrow}=[<-, >=stealth, shorten <=.03cm,line width=1.5] + + + + + % + \tikzset{ % + oriented WD/.style={% + every to/.style={ + out=0,in=180,draw + }, + label/.style={ + font=\everymath\expandafter{\the\everymath\scriptstyle}, + inner sep=0pt, + node distance=2pt and -2pt + }, + semithick, + node distance=1 and 1, + decoration={ + markings, mark=at position \stringdecpos with \stringdec + }, + ar/.style={ + postaction={decorate} + }, + execute at begin picture={ + \tikzset{ + x=\bbx, y=\bby, + every fit/.style={ + inner xsep=\bbx, inner ysep=\bby + } + } + } + }, + string decoration/.store in=\stringdec, + string decoration={ + \arrow{stealth}; + }, + string decoration pos/.store in=\stringdecpos, + string decoration pos=.7, + bbx/.store in=\bbx, + bbx = 1.5cm, + bby/.store in=\bby, + bby = 1.5ex, + bb port sep/.store in=\bbportsep, + bb port sep=1.5, + bb port length/.store in=\bbportlen, + bb port length=4pt, + bb penetrate/.store in=\bbpenetrate, + bb penetrate=0, + bb min width/.store in=\bbminwidth, + bb min width=1cm, + bb rounded corners/.store in=\bbcorners, + bb rounded corners=2pt, + bb small/.style={ + bb port sep=1, + bb port length=2.5pt, + bbx=.4cm, bb min width=.4cm, + bby=.7ex + }, + bb medium/.style={ + bb port sep=1, + bb port length=2.5pt, + bbx=.4cm, + bb min width=.4cm, + bby=.9ex + }, + bb/.code 2 args={% + \pgfmathsetlengthmacro{\bbheight}{\bbportsep * (max(#1,#2)+1) * \bby} + \pgfkeysalso{ + draw, + minimum height=\bbheight, + minimum width=\bbminwidth, + outer sep=0pt, + rounded corners=\bbcorners, + thick, + prefix after command={ + \pgfextra{\let\fixname\tikzlastnode} + }, + append after command={ + \pgfextra{ + \draw + \ifnum #1=0 + {} + \else + foreach \i in {1,...,#1} { + ($(\fixname.north west)!{\i/(#1+1)}!(\fixname.south west)$) +(- + \bbportlen,0) + coordinate (\fixname_in\i) -- +(\bbpenetrate,0) coordinate (\fixname_in\i') + } + \fi + % + \ifnum + #2=0{} + \else + foreach \i in {1,...,#2} { + ($(\fixname.north east)!{\i/(#2+1)}!(\fixname.south east)$) +(- + \bbpenetrate,0) + coordinate (\fixname_out\i') -- +(\bbportlen,0) coordinate (\fixname_out\i) + } + \fi; + } + } + } + }, + bb name/.style={ + append after command={ + \pgfextra{ + \node[anchor=north] at (\fixname.north) {#1} + ;} + } + } + } + + \begin{document} + +\scalebox{3}{ +\begin{tikzpicture}[oriented WD, bb port length=10pt, baseline=1em] + % + \node[bb={1}{1}, fill={black!20}] (X1) at (0,4) {$f$}; + \node[bb={1}{1}, fill={black!20}] (X2) at (1,0) {$g$}; + \node[] (A1) at (-0.75,4) {}; + \node[] (A2) at (-0.75,0) {}; + \node[] (B1) at (1.75,4) {}; + \node[] (B2) at (1.75,0) {}; + % + % + \draw[label] + node [left=2pt of A1] {$A_1$} + node [left=2pt of A2] {$A_2$} + node [right=2pt of B1] {$B_1$} + node [right=2pt of B2] {$B_2$} + (A1) -- (X1_in1) + (A2) -- (X2_in1) + (X1_out1) -- (B1) + (X2_out1) -- (B2); + % +\end{tikzpicture} + += + +\begin{tikzpicture}[oriented WD, bb port length=10pt, baseline=1em] + % + \node[bb={1}{1}, fill={black!20}] (X1) at (1,4) {$f$}; + \node[bb={1}{1}, fill={black!20}] (X2) at (0,0) {$g$}; + \node[] (A1) at (-0.75,4) {}; + \node[] (A2) at (-0.75,0) {}; + \node[] (B1) at (1.75,4) {}; + \node[] (B2) at (1.75,0) {}; + % + % + \draw[label] + node [left=2pt of A1] {$A_1$} + node [left=2pt of A2] {$A_2$} + node [right=2pt of B1] {$B_1$} + node [right=2pt of B2] {$B_2$} + (A1) -- (X1_in1) + (A2) -- (X2_in1) + (X1_out1) -- (B1) + (X2_out1) -- (B2); + % +\end{tikzpicture} +}{} + + +\end{document} \ No newline at end of file diff --git a/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/PetriConflict.tex b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/PetriConflict.tex new file mode 100644 index 0000000..e0c6e16 --- /dev/null +++ b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/PetriConflict.tex @@ -0,0 +1,238 @@ + +\documentclass{standalone} +\usepackage{tikz} +\usepackage{amsfonts} +\usepackage{amssymb} % Extra mathematical symbols (loads amsfonts) + % + \usepackage{tikz} % + \usetikzlibrary{ + petri, % + backgrounds, % + arrows, % + positioning, % + decorations.markings, % + calc, % + fit, % + } +\def\backgrnd{black!20} % Background for Tikz pictures +\pgfdeclarelayer{edgelayer} +\pgfdeclarelayer{nodelayer} +\pgfdeclarelayer{background} +\pgfsetlayers{background, edgelayer,nodelayer,main} +\tikzstyle{place}= +[circle,thick,draw=blue!75,fill=blue!20,minimum size=6mm] +\tikzstyle{antiplace}= +[circle,thick,draw=red!75,fill=red!20,minimum size=6mm] +\tikzstyle{transition}= +[rectangle,thick,draw=black!75,fill=black!20,minimum size=4mm] +\tikzstyle{inarrow}=[->, >=stealth, shorten >=.03cm,line width=0.5] +\tikzstyle{outarrow}=[<-, >=stealth, shorten <=.03cm,line width=1.5] + +\tikzset{ + pics/netA/.style args={#1/#2/#3/#4/#5/#6}{code={ + + + % \fill[yellow!15] (-0.8,-2.3) rectangle (2.3, 2.3); + + % X + \node [place,label=above right:$X$,colored tokens={% + #1 + }] (-p_x) {}; + + % Tau + \node [transition,label=above:$\tau$, label=left:#4] (-t_tau) [above = of -p_x] {}; + + % Y + \node [place,label=above:$Y$,colored tokens={% + #2 + }] (-p_y) [right=of -t_tau] {}; + + % Mu + \node [transition,label=below:$\mu$, label=right:#5] (-t_mu) [below = of -p_y] {}; + + % Nu + \node [transition,label=below:$\nu$, label=left:#6] (-t_nu) [below =of -p_x] {}; + + % Z + \node [place,label=below:$Z$,colored tokens={% + #3 + }] (-p_z) [right=of -t_nu] {}; + + \draw[->] (-p_x) -- (-t_tau); + \draw[->] (-t_tau) -- (-p_y); + \draw[->] (-p_y) -- (-t_mu); + \draw[->] (-t_mu) -- (-p_x); + \draw[->] (-p_x) -- (-t_nu); + \draw[->] (-t_nu) -- (-p_z); + + }} +} + + % + \tikzset{ % + oriented WD/.style={% + every to/.style={ + out=0,in=180,draw + }, + label/.style={ + font=\everymath\expandafter{\the\everymath\scriptstyle}, + inner sep=0pt, + node distance=2pt and -2pt + }, + semithick, + node distance=1 and 1, + decoration={ + markings, mark=at position \stringdecpos with \stringdec + }, + ar/.style={ + postaction={decorate} + }, + execute at begin picture={ + \tikzset{ + x=\bbx, y=\bby, + every fit/.style={ + inner xsep=\bbx, inner ysep=\bby + } + } + } + }, + string decoration/.store in=\stringdec, + string decoration={ + \arrow{stealth}; + }, + string decoration pos/.store in=\stringdecpos, + string decoration pos=.7, + bbx/.store in=\bbx, + bbx = 1.5cm, + bby/.store in=\bby, + bby = 1.5ex, + bb port sep/.store in=\bbportsep, + bb port sep=1.5, + bb port length/.store in=\bbportlen, + bb port length=4pt, + bb penetrate/.store in=\bbpenetrate, + bb penetrate=0, + bb min width/.store in=\bbminwidth, + bb min width=1cm, + bb rounded corners/.store in=\bbcorners, + bb rounded corners=2pt, + bb small/.style={ + bb port sep=1, + bb port length=2.5pt, + bbx=.4cm, bb min width=.4cm, + bby=.7ex + }, + bb medium/.style={ + bb port sep=1, + bb port length=2.5pt, + bbx=.4cm, + bb min width=.4cm, + bby=.9ex + }, + bb/.code 2 args={% + \pgfmathsetlengthmacro{\bbheight}{\bbportsep * (max(#1,#2)+1) * \bby} + \pgfkeysalso{ + draw, + minimum height=\bbheight, + minimum width=\bbminwidth, + outer sep=0pt, + rounded corners=\bbcorners, + thick, + prefix after command={ + \pgfextra{\let\fixname\tikzlastnode} + }, + append after command={ + \pgfextra{ + \draw + \ifnum #1=0 + {} + \else + foreach \i in {1,...,#1} { + ($(\fixname.north west)!{\i/(#1+1)}!(\fixname.south west)$) +(- + \bbportlen,0) + coordinate (\fixname_in\i) -- +(\bbpenetrate,0) coordinate (\fixname_in\i') + } + \fi + % + \ifnum + #2=0{} + \else + foreach \i in {1,...,#2} { + ($(\fixname.north east)!{\i/(#2+1)}!(\fixname.south east)$) +(- + \bbpenetrate,0) + coordinate (\fixname_out\i') -- +(\bbportlen,0) coordinate (\fixname_out\i) + } + \fi; + } + } + } + }, + bb name/.style={ + append after command={ + \pgfextra{ + \node[anchor=north] at (\fixname.north) {#1} + ;} + } + } + } + + + + +\begin{document} +\scalebox{3}{ +\begin{tikzpicture} + \pgfmathsetmacro\bS{3.5} + \pgfmathsetmacro\hkX{(\bS/3.5)} + \pgfmathsetmacro\kY{-1.5} + \pgfmathsetmacro\hkY{\kY*0.5} + + \draw pic (m0) at (0,0) {netA={{black}/{}/{}/{}/{}/{}}}; + \draw pic (m1) at (\bS,0) {netA={{}/{black}/{}/{$\blacktriangleright$}/{}/{}}}; + \draw pic (m2) at ({2 * \bS},0) {netA={{black,red}/{black}/{}/{}/{}/{}}}; + \draw pic (m3) at ({3 * \bS},0) {netA={{red}/{black}/{black}/{}/{}/{$\blacktriangleright$}}}; + \draw pic (m4) at ({4 * \bS},0) {netA={{black, red}/{}/{black}/{}/{$\blacktriangleleft$}/{}}}; + \draw pic (m5) at ({5 * \bS},0) {netA={{}/{}/{black}/{}/{}/{}}}; + + \begin{scope}[very thin] + \foreach \j in {1,...,5} { + \pgfmathsetmacro \k { \j * \bS - 1 }; + \draw[gray,dashed] (\k,-3) -- (\k,-8); + \draw[gray] (\k,3) -- (\k,-3); + } + \end{scope} + + \begin{scope}[shift={(0,-4)}, oriented WD, bbx = 1cm, bby =.4cm, bb min width=1cm, bb port sep=1] + % [,oriented WD,bbx = 1cm, bby =.5cm, bb min width=1cm,bb port length=4pt, bb port sep=1] + + \draw node [fill=\backgrnd,bb={1}{1}] (Tau) at (\bS - 1,0) {$\tau$}; + \draw node [fill=\backgrnd,bb={1}{1}] (Mu) at ({4 * \bS - 1},0) {$\mu$}; + \draw node [fill=\backgrnd,bb={1}{1}] (Nu) at ({3 * \bS - 1},{2 * \kY}) {$\nu$}; + + \draw (-2,0) -- node[above] {$X$} (0,0) + -- node[above] {} (Tau_in1); + + \draw (Tau_out1) -- node[above] {$Y$} ({2 * \bS - 1},0) + -- node[above] {$Y$} ({3 * \bS - 1},0) + -- node[above] {$Y$} (Mu_in1); + + \draw (Mu_out1) -- node[above] {$X$} ({5 * \bS - 1},0) + -- node[above] {} ({5 * \bS - 1},0) + to[out=0, in=90] node[above] {} ({5 * \bS},-0.75) + to[out=-90,in=0] node[below] {} ({5 * \bS - 1},{\kY}) + -- node[above] {} ({5 * \bS - 1},{\kY}) + -- node[above] {$X^{-1}$} ({4 * \bS - 1},{\kY}) + -- node[above] {$X^{-1}$} ({3 * \bS - 1},{\kY}) + -- node[above] {$X^{-1}$} ({2 * \bS - 1},{\kY}) + to[out=-180,in=90] node[above] {} ({2 * \bS - 2},{2 * \kY - \hkY}) + to[out=-90,in=-180] node[above] {} ({2 * \bS - 1},{2 * \kY}) + -- node[above] {$X$} (Nu_in1); + + \draw (Nu_out1) -- node[above] {$Z$} ({4 * \bS - 1},{2 * \kY}) + -- node[above] {$Z$} ({5 * \bS - 1},{2 * \kY}) + -- node[above] {} ({6 * \bS - 1},{2 * \kY}) + -- node[above] {$Z$} ({6 * \bS},{2 * \kY}); + + \end{scope} +\end{tikzpicture}} +\end{document} \ No newline at end of file diff --git a/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/PetriNetExecution.tex b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/PetriNetExecution.tex new file mode 100644 index 0000000..bcc8a0d --- /dev/null +++ b/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/tex/PetriNetExecution.tex @@ -0,0 +1,224 @@ + +\documentclass{standalone} +\usepackage{tikz} +\usepackage{amsfonts} + + % + \usepackage{tikz} % + \usetikzlibrary{ + petri, % + backgrounds, % + arrows, % + positioning, % + decorations.markings, % + calc, % + fit, % + } +\def\backgrnd{black!20} % Background for Tikz pictures +\pgfdeclarelayer{edgelayer} +\pgfdeclarelayer{nodelayer} +\pgfdeclarelayer{background} +\pgfsetlayers{background, edgelayer,nodelayer,main} +\tikzstyle{place}= +[circle,thick,draw=blue!75,fill=blue!20,minimum size=6mm] +\tikzstyle{antiplace}= +[circle,thick,draw=red!75,fill=red!20,minimum size=6mm] +\tikzstyle{transition}= +[rectangle,thick,draw=black!75,fill=black!20,minimum size=4mm] +\tikzstyle{inarrow}=[->, >=stealth, shorten >=.03cm,line width=0.5] +\tikzstyle{outarrow}=[<-, >=stealth, shorten <=.03cm,line width=1.5] + +\tikzset{ + pics/netA/.style args={#1/#2/#3/#4/#5/#6/#7}{code={ + % \fill[yellow!15] (-0.8,-2.3) rectangle (2.3, 2.3); + + \node [place,label=above:$p_1$, tokens={% + #1 + }] (-pl_1) {}; + + \node [transition,label=above:$t$, label=below:#5] (-tr_1) [right = of -pl_1] {}; + + \node [place,label=above:$p_2$, tokens={% + #2 + }] (-pl_2) [right = of -tr_1] {}; + + \node [transition,label=left:$v$, label=above:#6] (-tr_2) [below = of -tr_1] {}; + \node [transition,label=below:$u$, label=above:#7] (-tr_3) [below = of -tr_2] {}; + + \node [place,label=below:$p_3$, tokens={% + #3 + }] (-pl_3) [left = of -tr_3] {}; + + \node [place,label=below:$p_4$, tokens={% + #4 + }] (-pl_4) [right = of -tr_3] {}; + + \draw[inarrow] (-pl_1) -- (-tr_1); + \draw[inarrow] (-tr_1) -- (-pl_2); + \draw[inarrow] (-pl_2) -- (-tr_2); + \draw[inarrow] (-tr_2) -- (-pl_3); + \draw[inarrow] (-tr_2) -- (-pl_4); + \draw[inarrow] (-pl_3) -- (-tr_3); + \draw[inarrow] (-tr_3) -- (-pl_4); + }} +} + + + % + \tikzset{ % + oriented WD/.style={% + every to/.style={ + out=0,in=180,draw + }, + label/.style={ + font=\everymath\expandafter{\the\everymath\scriptstyle}, + inner sep=0pt, + node distance=2pt and -2pt + }, + semithick, + node distance=1 and 1, + decoration={ + markings, mark=at position \stringdecpos with \stringdec + }, + ar/.style={ + postaction={decorate} + }, + execute at begin picture={ + \tikzset{ + x=\bbx, y=\bby, + every fit/.style={ + inner xsep=\bbx, inner ysep=\bby + } + } + } + }, + string decoration/.store in=\stringdec, + string decoration={ + \arrow{stealth}; + }, + string decoration pos/.store in=\stringdecpos, + string decoration pos=.7, + bbx/.store in=\bbx, + bbx = 1.5cm, + bby/.store in=\bby, + bby = 1.5ex, + bb port sep/.store in=\bbportsep, + bb port sep=1.5, + bb port length/.store in=\bbportlen, + bb port length=4pt, + bb penetrate/.store in=\bbpenetrate, + bb penetrate=0, + bb min width/.store in=\bbminwidth, + bb min width=1cm, + bb rounded corners/.store in=\bbcorners, + bb rounded corners=2pt, + bb small/.style={ + bb port sep=1, + bb port length=2.5pt, + bbx=.4cm, bb min width=.4cm, + bby=.7ex + }, + bb medium/.style={ + bb port sep=1, + bb port length=2.5pt, + bbx=.4cm, + bb min width=.4cm, + bby=.9ex + }, + bb/.code 2 args={% + \pgfmathsetlengthmacro{\bbheight}{\bbportsep * (max(#1,#2)+1) * \bby} + \pgfkeysalso{ + draw, + minimum height=\bbheight, + minimum width=\bbminwidth, + outer sep=0pt, + rounded corners=\bbcorners, + thick, + prefix after command={ + \pgfextra{\let\fixname\tikzlastnode} + }, + append after command={ + \pgfextra{ + \draw + \ifnum #1=0 + {} + \else + foreach \i in {1,...,#1} { + ($(\fixname.north west)!{\i/(#1+1)}!(\fixname.south west)$) +(- + \bbportlen,0) + coordinate (\fixname_in\i) -- +(\bbpenetrate,0) coordinate (\fixname_in\i') + } + \fi + % + \ifnum + #2=0{} + \else + foreach \i in {1,...,#2} { + ($(\fixname.north east)!{\i/(#2+1)}!(\fixname.south east)$) +(- + \bbpenetrate,0) + coordinate (\fixname_out\i') -- +(\bbportlen,0) coordinate (\fixname_out\i) + } + \fi; + } + } + } + }, + bb name/.style={ + append after command={ + \pgfextra{ + \node[anchor=north] at (\fixname.north) {#1} + ;} + } + } + } + + + + +\begin{document} +\scalebox{3}{ +\begin{tikzpicture} + \pgfmathsetmacro\bS{5} + \pgfmathsetmacro\hkX{(\bS/3.5)} + \pgfmathsetmacro\kY{-1.5} + \pgfmathsetmacro\hkY{\kY*0.5} + \draw pic (m0) at (0,0) {netA={{1}/{1}/{2}/{0}/{}/{}/{}}}; + \draw pic (m1) at (\bS,0) {netA={{0}/{2}/{2}/{0}/{}/{}/{}}}; + \draw pic (m2) at ({2 * \bS},0) {netA={{0}/{1}/{3}/{1}/{}/{}/{}}}; + \draw pic (m3) at ({3 * \bS},0) {netA={{0}/{1}/{2}/{2}/{}/{}/{}}}; + \begin{scope}[very thin] + \foreach \j in {1,...,3} { + \pgfmathsetmacro \k { \j * \bS - 1 }; + \draw[gray,dashed] (\k,-4) -- (\k,-8.25); + \draw[gray] (\k,1) -- (\k,-4); + } + \end{scope} + \begin{scope}[shift={(0,-4)}, oriented WD, bbx = 1cm, bby =.4cm, bb min width=1cm, bb port sep=1.5] + \draw node [fill=\backgrnd,bb={1}{1}] (Tau) at (\bS -1,-1) {$t$}; + \draw node [fill=\backgrnd,bb={1}{2}, ] (Mu) at ({2 * \bS - 1},-1) {$v$}; + \draw node [fill=\backgrnd,bb={1}{1}] (Nu) at ({3 * \bS - 1},{2 * \kY}) {$u$}; + \draw (-1,-1) -- node[above] {$p_1$} (0,-1) + -- node[above] {} (Tau_in1); + \draw (-1,-2) -- node[above] {$p_2$} (0,-2) -- (\bS-1, -2); + \draw (-1,-3) -- node[above] {$p_3$} (0,-3) -- (\bS-1, -3); + \draw (-1,-4) -- node[above] {$p_3$} (0,-4) -- (\bS-1, -4); + \draw (Tau_out1) -- node[above] {$p_2$} (Mu_in1); + \draw (\bS-1,-2) -- (2*\bS-1, -2); + \draw (\bS-1,-3) -- (2*\bS-1, -3); + \draw (\bS-1,-4) -- (2*\bS-1, -4); + \draw (Mu_out1) -- (3*\bS-1, -0.725); + \draw (Mu_out2) -- (3*\bS-1, -1.325); + \draw (2*\bS-1,-2) -- (3*\bS-1, -2); + \draw (2*\bS-1,-3) -- (Nu_in1); + \draw (2*\bS-1,-4) -- (3*\bS-1, -4); + \draw (3*\bS-1,-0.725) to (4*\bS-2, -0.725) -- node[above] {$p_3$} (4*\bS-1, -0.725); + \draw (3*\bS-1,-1.325) -- (3*\bS,-1.325) to (4*\bS-2, -1.325) -- node[above] {$p_4$} (4*\bS-1, -1.325); + \draw (3*\bS-1,-2) to (4*\bS-2, -2) -- node[above] {$p_2$} (4*\bS-1, -2); + \draw (Nu_out1) to (4*\bS-2, -3) -- node[above] {$p_4$} (4*\bS-1, -3); + \draw (3*\bS-1,-4) to (4*\bS-2, -4) -- node[above] {$p_3$} (4*\bS-1, -4); + \end{scope} +\end{tikzpicture} +}{} + + +\end{document} \ No newline at end of file From 2147c734fec9644b233b22807f44b1b5356e9abc Mon Sep 17 00:00:00 2001 From: Fabrizio Romano Genovese Date: Fri, 5 Jan 2024 14:14:45 +0100 Subject: [PATCH 2/7] Thumbnail image changed. --- _posts/2024-01-05-correctly-pricing-txs-parallel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2024-01-05-correctly-pricing-txs-parallel.md b/_posts/2024-01-05-correctly-pricing-txs-parallel.md index 4ffd959..853eeb2 100644 --- a/_posts/2024-01-05-correctly-pricing-txs-parallel.md +++ b/_posts/2024-01-05-correctly-pricing-txs-parallel.md @@ -4,7 +4,7 @@ title: Correctly pricing blockspace in a causally parallel world author: Fabrizio Genovese, Daniele Palombi categories: [parallelization, causality, MEV, EVM, Jito] excerpt: Where we investigate the thread that ties Jito, the parallel EVM, auction theory and physics together. -image: assetsPosts/2023-07-26-lagrangian-intent-search-i/greedyAction.png +image: assetsPosts/2024-01-05-correctly-pricing-txs-parallel/PetriConflict.png usemathjax: true thanks: --- From fba556a8f86d6895da54d594bd52e5e70369a059 Mon Sep 17 00:00:00 2001 From: Fabrizio Romano Genovese Date: Fri, 5 Jan 2024 14:16:50 +0100 Subject: [PATCH 3/7] Small fixes. --- _posts/2024-01-05-correctly-pricing-txs-parallel.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/_posts/2024-01-05-correctly-pricing-txs-parallel.md b/_posts/2024-01-05-correctly-pricing-txs-parallel.md index 853eeb2..104a0a2 100644 --- a/_posts/2024-01-05-correctly-pricing-txs-parallel.md +++ b/_posts/2024-01-05-correctly-pricing-txs-parallel.md @@ -53,27 +53,27 @@ Tarun is definitely on the right track when he points out in his thread that tra A world where only sequential composition is possible is mathematically called *category*. This is a term you read multiple times on this blog, but in a nutshell it means that you have processes changing state, represented as boxes: -![Some processes and states.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/Boxes.png) +![A graphical depiction of some processes and states.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/Boxes.png) And that processes can be piped together in the obvious way (here $g$ acts on the state changed by $f$): -![Process composition.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/BoxesMerged.png) +![A graphical depiction of process composition.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/BoxesMerged.png) From a very high-level perspective, categories are generated by graphs, which are the underlying topologies of *finite state machines*. Indeed, as you will probably know, a finite state machine has just one monolithic state, which you operate on sequentially. Here causality is really boring, as 'there is not much to do', and the ordering between transactions is fully established. Things become much more interesting when we add another dimension, obtaining what is called a *monoidal category*. Here state can be split in multiple components - represented as different wires - and processes can act on different wires at the same time: -![Monoidal processes and states.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/BoxesMonoidal.png) +![A graphical depiction of processes and states in a monoidal category.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/BoxesMonoidal.png) One of the main tenets of monoidal categories is the [Eckmann-Hilton argument](https://en.wikipedia.org/wiki/Eckmann%E2%80%93Hilton_argument), which essentially says that 'two processes modifying non overlapping threads have no causal relation'. Graphically, this means we can slide these processes past to each other: -![Eckmann-Hilton.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/EckmannHilton.png) +![A graphical depiction of the Eckmann-Hilton argument.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/EckmannHilton.png) Monoidal categories in their most general form are generated by *hypergraphs*, which - [modulo some very deep but boring caveats](https://arxiv.org/abs/2101.04238) - are the underlying topologies of [Petri nets](https://core.ac.uk/download/pdf/82342688.pdf), a very famous model of concurrent systems. An example of how a parallel computation in a Petri net is expressed in terms of monoidal categories can be seen below from the following picture from [a paper of ours](https://arxiv.org/abs/2101.09100): -![image description](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/PetriNetExecution.png) +![Graphical depiction of how computations in a Petri net correspond to string diagrams in a monoidal category.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/PetriNetExecution.png) As you can see, in the net you can fire $t$ and $u$ independently, and indeed the corresponding $t$ and $u$ processes in the 'string diagram' can be slid one past the other. On the other hand, you can decide if you want $v$ to use the state that was already in $p_2$ or if you want it to use the one generated by $t$ (as we do above). The two choices originate different causal structures (different DAGs in Tarun's language) and generate different diagrams that cannot be homotopically deformed one into the other. @@ -96,7 +96,7 @@ Stitching the (parallel) execution and the (parallel) MEV/auction layer together The causality story runs really deep and there are much more complex forms of causality that we already have the tools to investigate. Interesting, the parallel 'maths - physics - models of computation - economics' keeps holding. Just to give an example, in Physics you have **teleportation**, where processes can go 'from the future to the past', yanking the causal flow of things. The computational analogue, which is probably a bit easier to grasp, is an extension of Petri nets where you can do state borrowing and error correction. In the picture below, again taken from [a paper of ours](https://arxiv.org/abs/1805.05988), the transition $\nu$ needs a state that hasn't been created yet. To proceed, it creates this state together with a 'debt' (represented by the red token). Now $\nu$ and $\tau$ can be computed in parallel. The consistency of the whole system is restored when $\mu$ is fired, providing the state $\nu$ requested and 'annihilating' the debt (yes, 'annihilation' as in particle-antiparticle annihilation is not a coincidence here). -![image description](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/PetriConflict.png) +![Graphical depiction of how extended Petri net executions correspond to string diagrams in a compact closed category.](/assetsPosts/2024-01-05-correctly-pricing-txs-parallel/PetriConflict.png) By 'yanking' the diagram, one can see that the causal flow of this computation is equivalent to firing $\tau$, then $\mu$, then $\nu$. These advanced forms of causality may be useful in intentland, where maybe we want to solve different intents 'in parallel' and then stitch them together afterwards. From 3c1b8ef9b376c0c88d5c11f4d31156707ab6c334 Mon Sep 17 00:00:00 2001 From: Philipp Zahn Date: Fri, 5 Jan 2024 14:25:46 +0100 Subject: [PATCH 4/7] Minor typos --- _posts/2024-01-05-correctly-pricing-txs-parallel.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2024-01-05-correctly-pricing-txs-parallel.md b/_posts/2024-01-05-correctly-pricing-txs-parallel.md index 853eeb2..b69efd4 100644 --- a/_posts/2024-01-05-correctly-pricing-txs-parallel.md +++ b/_posts/2024-01-05-correctly-pricing-txs-parallel.md @@ -29,7 +29,7 @@ Clearly, there are some tasks that are highly parallelizable - e.g. bruteforcing Now, our idea is very simple. Parallelization is good because it makes execution faster. As such, one would like to incentivize blocks that are 'as parallel as possible'. Furthermore, we must pair the computation layer with the economic layer, and the way we do it is via *transaction fees*: We put a cost on each transaction that should be proportional to how much (space, computational) resources the transaction consumes, and to how badly the user wants that transaction to be included in a block. -Naïvely, we'd like 'highly parallelizable' transactions to be cheaper as the amount of computation one must do is more efficient. Paradoxically, this is easier said than done, and depends on the fact that fees represent costs for some actors, but revenues for others. If we were to make 'highly parallel transactions' fees cheaper - e.g. by multiplying the transaction gas size by a 'parallelization coefficient' ranging from 0 to 1 - we would incentivize one end of the pipeline (end users, dapp developers) to push for highly parallel blocks. At the same time, we would incentivate the other end of the pipeline (the fee recipitents, so validators, builders, etc) to reject highly parallel blocks in favor of sequential ones, just because they pay better. +Naïvely, we'd like 'highly parallelizable' transactions to be cheaper as the amount of computation one must do is more efficient. Paradoxically, this is easier said than done, and depends on the fact that fees represent costs for some actors, but revenues for others. If we were to make 'highly parallel transactions' fees cheaper - e.g. by multiplying the transaction gas size by a 'parallelization coefficient' ranging from 0 to 1 - we would incentivize one end of the pipeline (end users, dapp developers) to push for highly parallel blocks. At the same time, we would incentivize the other end of the pipeline (the fee recipients, so validators, builders, etc) to reject highly parallel blocks in favor of sequential ones, just because they pay better. This has the very counterintuitive effect that if a user really wants a transaction to be included, they could stand a better chance by just opting for a highly sequential implementation of whatever they want to do (e.g. using a bad, gas guzzling unparallelized dapp instead of a nice one). @@ -102,4 +102,4 @@ By 'yanking' the diagram, one can see that the causal flow of this computation i So should you hear about 'self-healing' or 'error correcting' parallel EVM in the future, let it be know that we squatted these terms first! :P -Ok, we hope we weren't too late to the party. Stay tuned for more updates! \ No newline at end of file +Ok, we hope we weren't too late to the party. Stay tuned for more updates! From 029637d6b30c0216d7b97201a96acc3e595955ec Mon Sep 17 00:00:00 2001 From: Fabrizio Romano Genovese Date: Fri, 5 Jan 2024 14:40:09 +0100 Subject: [PATCH 5/7] Small edit. --- _posts/2024-01-05-correctly-pricing-txs-parallel.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/_posts/2024-01-05-correctly-pricing-txs-parallel.md b/_posts/2024-01-05-correctly-pricing-txs-parallel.md index 1c0f432..9ab4d17 100644 --- a/_posts/2024-01-05-correctly-pricing-txs-parallel.md +++ b/_posts/2024-01-05-correctly-pricing-txs-parallel.md @@ -31,7 +31,14 @@ Now, our idea is very simple. Parallelization is good because it makes execution Naïvely, we'd like 'highly parallelizable' transactions to be cheaper as the amount of computation one must do is more efficient. Paradoxically, this is easier said than done, and depends on the fact that fees represent costs for some actors, but revenues for others. If we were to make 'highly parallel transactions' fees cheaper - e.g. by multiplying the transaction gas size by a 'parallelization coefficient' ranging from 0 to 1 - we would incentivize one end of the pipeline (end users, dapp developers) to push for highly parallel blocks. At the same time, we would incentivize the other end of the pipeline (the fee recipients, so validators, builders, etc) to reject highly parallel blocks in favor of sequential ones, just because they pay better. -This has the very counterintuitive effect that if a user really wants a transaction to be included, they could stand a better chance by just opting for a highly sequential implementation of whatever they want to do (e.g. using a bad, gas guzzling unparallelized dapp instead of a nice one). +One consequence of this is that whatever gas pricing mechanism we adopt, it cannot be too naïve. One possible way to align agents across the pipeline would be the following: +- As transaction fees, users specify gas for the 'worst case scenario', when the transaction is not parallelizable at all; +- At block simulation, a certain degree of parallelization is established as a function of the block; +- The users receive a discount on their fee based on this; +- The block builder receives instead the whole value of the user transaction, maybe plus a small bonus; +- The delta between what the user pays and what the builder receives is simply created, as block rewards are created now. + +We are not claiming that this is the right way to do it. The example above only shows how one must be a bit creative when it comes to incentive design to make sure all actors are aligned. Luckily for us, there's a vast literature on topics such as cloud infrastructure pricing that we can boorrow from, so we don't have to start from scratch. We will probably come up with some follow-up posts about this in the future. ## A story of ordering From ad201d1c014f520247e89befee323691371666c7 Mon Sep 17 00:00:00 2001 From: Fabrizio Romano Genovese Date: Fri, 5 Jan 2024 14:41:12 +0100 Subject: [PATCH 6/7] Cosmetics. --- _posts/2024-01-05-correctly-pricing-txs-parallel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2024-01-05-correctly-pricing-txs-parallel.md b/_posts/2024-01-05-correctly-pricing-txs-parallel.md index 9ab4d17..20ada07 100644 --- a/_posts/2024-01-05-correctly-pricing-txs-parallel.md +++ b/_posts/2024-01-05-correctly-pricing-txs-parallel.md @@ -35,7 +35,7 @@ One consequence of this is that whatever gas pricing mechanism we adopt, it cann - As transaction fees, users specify gas for the 'worst case scenario', when the transaction is not parallelizable at all; - At block simulation, a certain degree of parallelization is established as a function of the block; - The users receive a discount on their fee based on this; -- The block builder receives instead the whole value of the user transaction, maybe plus a small bonus; +- The block builder instead receives the whole value of the user transaction, maybe plus a small bonus; - The delta between what the user pays and what the builder receives is simply created, as block rewards are created now. We are not claiming that this is the right way to do it. The example above only shows how one must be a bit creative when it comes to incentive design to make sure all actors are aligned. Luckily for us, there's a vast literature on topics such as cloud infrastructure pricing that we can boorrow from, so we don't have to start from scratch. We will probably come up with some follow-up posts about this in the future. From 777a27a80e7f962a74970d9ee505dec18e078e7e Mon Sep 17 00:00:00 2001 From: Fabrizio Romano Genovese Date: Fri, 5 Jan 2024 14:41:52 +0100 Subject: [PATCH 7/7] Cosmetics. --- _posts/2024-01-05-correctly-pricing-txs-parallel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2024-01-05-correctly-pricing-txs-parallel.md b/_posts/2024-01-05-correctly-pricing-txs-parallel.md index 20ada07..41b7205 100644 --- a/_posts/2024-01-05-correctly-pricing-txs-parallel.md +++ b/_posts/2024-01-05-correctly-pricing-txs-parallel.md @@ -38,7 +38,7 @@ One consequence of this is that whatever gas pricing mechanism we adopt, it cann - The block builder instead receives the whole value of the user transaction, maybe plus a small bonus; - The delta between what the user pays and what the builder receives is simply created, as block rewards are created now. -We are not claiming that this is the right way to do it. The example above only shows how one must be a bit creative when it comes to incentive design to make sure all actors are aligned. Luckily for us, there's a vast literature on topics such as cloud infrastructure pricing that we can boorrow from, so we don't have to start from scratch. We will probably come up with some follow-up posts about this in the future. +We are not claiming that this is the right way to do it (and indeed it's not, because it may require to sequentially simulate the block to calculate the improvement coefficient, that defies the purpose of parallelization completely). The example above only shows how one must be a bit creative when it comes to incentive design to make sure all actors are aligned. Luckily for us, there's a vast literature on topics such as cloud infrastructure pricing that we can boorrow from, so we don't have to start from scratch. We will probably come up with some follow-up posts about this in the future. ## A story of ordering