 I'm Philip Kant, I work at IHK and lead the group that is introducing formal methods into the software development methodology and the idea of that group is to make sure that the results of the researchers who write papers and improve things about the protocols at a very abstract level and in a language that's suitable for writing papers and conveying information between humans and that in the process of translating that into something that is a machine executable that the computer can understand and that has all those details that are not really relevant for the protocols at a high level but are of course needed for the software to actually work that nothing gets lost in that translation process. In the blockchain industry IHK is pretty unique in applying formal methods, it's something that you would usually do in aerospace or for clinical, for medicine products or something for systems where there's high value or even harm to life at stake and in blockchain systems there's large value so we think that it's just reasonable to do this here as well. Okay, so thanks for inviting me, it's nice to be in Hamburg and talk about the stuff that we're working on and I'll do actually the introduction to Carano and the talk about formal methods that we're applying there in one go so the first half of the talk will be about in general what Carano is about and the consensus protocol about it behind it and then I'll go a bit into the methodology that we're introducing in developing software there and in the formal methods group we're already, we also get some assistance from experts from a few consultancies from world-type and prediction network solutions and actually tweak who's log why I didn't, I forgot to put on here so a few words about IHK, we are the company that built the Carano blockchain and we're very research focused so in the blockchain space you have all these, you touch various disciplines, you have cryptography, you have game theory and you have economics and so we try to collaborate with actual researchers and have an exchange with them and use their work, put it to production, give them feedback on what does work and what maybe some problems are that occur in practice and that they should think about and that would be worthwhile to investigate. We're heavily invested in functional programming so Carano is built using Haskell and I was told that there's also some Haskell people here in this meetup so that might be interesting and we're also working completely distributed so we have people in the US, we have people in Europe, in Asia and everybody works where they are and yeah. So what is Carano? It's a proof of stake blockchain and I'm going to explain a bit more about proof of work and proof of stake in a minute and it runs the cryptocurrency called ADA and besides running a cryptocurrency there's also lots of interesting things that we're planning to do on our roadmap. We are going to add smart contracts to the system and we're going to use different frameworks there. We are developing our own language called Plutus and we also use the K framework and the L.A. virtual machine which will make it possible for people to write smart contracts in all kinds of languages that are already established. We'll also introduce side chains for different reasons so that's different blockchains basically that run more or less independently of one another but they can share information, they can talk to each other, they can transfer trust from one chain to the other and one of the ideas that we will use them for is scalability because blockchains don't scale very well and by basically distributing the work across multiple blockchains you can gain some scalability. Another thing is that these smart contracts that you have on Ethereum and other platforms they tend to have some exploits from time to time where people find weaknesses and that's just if you have a system and you let people write their own code then it's easier to find some exploits and you have a much larger tech surface and the idea that we'll follow for Cardano is that we will have a settlement layer which is basically which does all the bookkeeping and then on top of that we will have compute layers where the smart contracts live and you have a small tech surface on the settlement layer because you don't have all those smart contracts there and we will try to keep the settlement layer for the basic bookkeeping as simple as possible and then add smart contracts on top of that but have a clear separation between those two and then long term what we'll also add is a treasury because blockchains are all about giving away control and not having a single authority that decides what happens but you create consensus between the users of the protocol and the thing is as long as you have some central authority that decides what gets implemented and funds the implementation and everything then you haven't reached that completely and the idea behind the treasury is that some of the funds that go into transaction fees and block rewards that some of this is set aside into a fund and then people who want to extend the system and want to write additional code can make a proposal and then the stakeholders can vote on which proposal should get funded by this money in the treasury. Right, so let me explain to you what proof of stake is about. So what do cryptocurrencies need a blockchain for? What's the thing that you want to achieve with a cryptocurrency? The main idea is that you have a currency that has no central authority that is in the hands of the users and nobody can tell people that they're not allowed to use the funds anymore, nobody can freeze funds and there should be no central authority that decides which transactions go into the ledger which ones are rejected that should all be decentralized and created by consensus. So decentralization and the lack of a central authority is a big thing that you want in cryptocurrencies. The other thing is that also everybody should have the possibility to join so there should be no, also nobody who could prevent anybody from saying okay I want to use this, I want to join this or I want to set up a node that contributes to the blockchain. There should be no barrier to entry and then of course what you need to have a currency is a stable ledger where you can put transactions in and there you also want two things. You need to have persistence so that transactions that are entered cannot vanish later on so that nobody can just say okay I sent you money and then afterwards it just disappears again. The other thing is liveness that when you submit a transaction to the system it should end up in the ledger after some time and all those requirements they are not easy to fulfill at the same time because you need something that's very stable and that people can trust but at the same time you don't want anybody to decide and to be the source, the single source of that trust. So blockchains are a way of creating trust without having a central authority. The most prominent example for this is bitcoin and so let me just show you a slide on how this works, on how trust is created on the bitcoin blockchain. So what the users of bitcoin do is they send transactions to the network and those transactions they are signed with a private key so nobody can spend other people's money but people want to make sure that transactions that they send get included and the transactions that they see there don't vanish again. So when you send those transactions to the system they get grouped into what's called blocks which are basically pages in a ledger and then they are also ordered by putting those blocks in order and each block references the block that comes before it by including the hash of the block and this ordering is important because what people could try to do is that they send the same money multiple times, they try to double spend or multiple spend their money and if you have an order between the transactions then you can decide which transaction is the valid one because the one that got there first is the one that's valid and if they try to spend their money again then they can't do it. So this ordering in the blockchain is important and the way that you achieve trust is that you say okay we don't have anybody who is the authority to write those blocks but you take turns and then if you take turns and you assume that not the whole world is or not the majority of the people conspire against you then when you send transaction to the ledger then at some point it will get included because not everybody will say okay I don't like this guy I will not include their transactions in the ledger. So by taking turns you can create a system where even if some people don't play by the rules the effect will be that you have a stable ledger where transactions get included and also the way that you prevent transactions from being deleted is that you say that if somebody would try to overwrite old transactions by for example sending a transaction where they spend a lot of money and then later on deciding that they didn't want to spend it after all and they got something in return for that money and they want to get rid of that transaction what they could do is to just create another block that references not the last block but the block before that. But if you take turns and then you also require that honest people just always take the longest chain then it gets increasingly harder to revert transactions if you go further down the blockchain because you would have to compete with a chain that's already there. Of course the problem with taking turns is we want to be permissionless so we don't want to say okay you can go in you can go in you can go in you and you can't and if you are permissionless and you don't check for identity of people then you also can prevent somebody for just from just registering multiple times and that's what's called the civil attack so somebody who would like to to attack this this setup they could just register 10,000 times and then if everybody just takes turn they would take 10,000 turns when anybody else would just take one turn and then it would be easy for them to revert all transactions. And so the solution that Bitcoin uses for that is to add a cost for registering and that cost is in the form of some basically some arbitrary mathematical puzzle so you see that all those blocks they include a hash to the previous block and what Bitcoin requires is if you want to write a block you can add some arbitrary data to the block some just some string of data and then you must do this in such a way that the hash of the block has a number of trail of leading zeros and this is something that you can just you can't since the the hash is not is not reversible you can you can't just compute what what kind of nonce you have to include here but you have to try it and try it again so you add some data and then you see okay the first digit is one and then you say okay you have to do it again and so you have to spend a lot of basically of of of hashing powers of computing power to try add some data compute the hash of the block if it fits your lucky you can submit it if not then you have to try again and so that adds a cost to registering and because of that cost it gets it gets expensive to attack the network because you would have to own more computers than than everybody else in the system and that's how how bitcoin creates trust so proof of work what does it how does it work you have basically a randomized leader election where you say that for every CPU that you add to the system you get one vote so it's a randomized you can view this as a randomized election where the chances of being elected is proportional to the amount of CPU power that you that you put into the system and then if you if you are lucky and you win this race then you get to write the block and there's some some rewards associated with that and we prevent to have to have all transactions being reverted by just saying that longest chain always wins and then as unless you have more CPUs than anybody else then it's hard to and it's exponentially hard to to revert old transactions the problems with that is that this this this hashing power has a huge energy consumption so the the energy consumption of the Bitcoin network is something on the order of a small national state and that all for just for just having a transaction rate of something like like 10 transactions per second or something like that and so the energy consumption is huge and it's also very hard to scale scale the system to to have something that has lot that has higher transaction rates and also because this race is basically a winner takes it all race so if you are lucky and solve this this this puzzle first then you have to create a block but everybody else who was busy trying to solve that that puzzle has to go on and solving a new puzzle because the next block will be different and so in order to maximize the chances of getting anything out of this race people work together and form pools and those pools lead to centralization again and the whole the whole thing that you that you wanted to have in a cryptocurrency is that you don't have a central authority and you you just have trust from a large collective of groups and if they if they group together to form a handful of mining pools then it's questionable whether you have really achieved that goal so the thing that you can look for is to have some some other scarce resource I mean the thing why why did we have this puzzle in the first place it was to prevent people from just registering multiple times and increasing the chances of being elected so the question is can we find another scarce resource that that we could use to basically decide who gets elected that is not as energy efficient and that doesn't lead to this to this large degree of centralization and the thing is we do have that resource because we have a cryptocurrency we have a currency on top of that ledger and that currency itself is a scarce resource there's a limited supply of coins and so what what we can do is that we can just say we we randomly pick one coin and the owner of that coin gets to write the new the next block and if we do that then basically in order to to have a higher chance of of getting elected for the next block you would have to buy more of the currency and that's also something that gets increasingly expensive just like buying buying server farms but it has the additional the additional advantage that it's tied to the system itself so if you if you are a large stakeholder and you bought lots of this currency then you have a better chance of attacking the system of subverting it of deleting transactions from the system but you wouldn't want to do so because if you did that and if people notice that you did that then you would devalue the currency and you have bought a lot of that currency so you are incentivized to be honest because if you play dishonestly and you are a large stakeholder then people will lose trust in the system and trust is ultimately what creates the value for this whole thing so this this scarce resource that that that basically protects us from the civil attack is actually very effective because it also incentivizes people to play honestly because people who have lots of that cryptocurrency in contrast to people who have bought lots of computers are actually would lose something if that particular currency got devalued the problem with that and the reason why it why it hasn't been used so far is that for this election process you need some randomness so for the for the proof of work you basically you have a random election and the randomness is basic it's just there it's it's it's implicit it's just whoever wins this race is elected but if you want to pick a random coin then you need an explicit random number generator you need to have some randomness and that has to be explicit and so there's two things that that you need there you need to all agree on the same source of randomness but then of course you if you had a central authority for that random number generator then that authority would again control large parts of the system because the random number generator in the end is the thing that that picks the coins and thereby picks the slot leaders and decides who can write blocks and so you don't want a central authority to to have control over the random number generator and the other thing that you also don't want to have is for anybody to be able to predict the random number generator because this randomly picking one coin it's basically lining up all the coins in the system and then producing random number and then picking the nth coin and if you could predict the random number generator then what you could do is that you could just send money across the system and try to get a distribution where your coins are at this place that will get chosen so you need you need two things for the random number generator you need a decentralized random number generator and one that cannot be predicted by people in advance before this election process and that's not an easy problem and that's that's why why proof of stake was often thought to be not as safe as proof of work now one one result from iOHK and the from the researchers at iOHK is this uroboros protocol uroboros is is a Greek mythological figure it's a snake that bites its own tail and why that is the name for the protocol will become clear when I describe it a bit and that's the first proof of stake protocol that has actual proofs of security so they wrote a paper and submitted it to a conference and other researchers looked at it and read their proofs and said okay this is this is fine for publication and the way that it works is that you split time into slots and each slot will have a block and for each of those slots one of the one of the stakeholders is randomly elected to be the leader for that slot and will have the right to create a block and for that you need you need some randomness and the way you do that is that you group those slots again into into epochs and before the start of an epoch all the stakeholders have to agree on some seed for the next random number generator and this is done in a way that basically the stakeholders themselves privately roll a dice and produce some some randomness and they they don't reveal it immediately to to the other parties so nobody can predict what the overall randomness will be and then at the end that what what they do is that they post to the blockchain a basically a proof that they already know what they have rolled and that they can no longer temper with and then once the stake for the next epoch is is clear what what that will be all the random numbers are revealed and are combined in a specified way and then you have a new seed so the seed is something that everybody has the ability to influence but nobody has the ability to predict because it's very it's it's many random numbers that are shared and nobody can just hold back their result and and just give the number that would have the effect of of influencing the random number generator in the way that they want because they everybody basically has to guarantee that they already rolled their dice and will no longer change it but but nobody sees what the others have a role it's it's like sitting at a table and rolling a dice and putting your hand over it and everybody sees that you have your hand over it and then you reveal it all at the same instant but it's it's in a distributed system so there's there's some some cryptography behind that where you basically have to prove that that what you what you will tell in the end is already what you committed to in the first place and this this protocol then is proven secure against adversaries that has that have less than half half of the stake which is basically the same as having more than half of the computing power in Bitcoin here is having more than half of the of the stakes of the of the amount of Ada in this in the system and what they did is basically look at sequences of slots and of sequences where you either have an honest party being the slot leader or it is honest party and then they basically look at sequences where it will be possible to create a fork that goes back a long time and then they they basically give guarantee they look that those kind of sequences are are rare and are hard to randomly produce and what the basically the the result for for the security is in one of the ways to present this is in formal table where you list the adversary strength so for Bitcoin this would be the the amount of computing power the fraction of the total computing power and for Cardano this would be the proportion of the stake that somebody owns and then you say how many minutes do I have to wait after a transaction enters the system in order to be 99% sure that this can no longer be reverted and then you see that for Bitcoin if an adversary has 10% of the hashing power you need to wait 50 minutes to have this 90% guarantee and for Roboros it's three to five minutes and this distinction here is if you if you require that the adversary only does things where nobody can see that he doesn't behave through the protocol because what one could do is do stuff like publish two separate blocks for the same slot which is against the protocol and if you did that everybody would just see that you are not behaving honestly right so so that's that's the the first provably secure proof of stake protocol and it is what we have running in production in Cardano and what basically what what we build upon what's creating the trust for us the next step in that there's always room for improvement is called Roboros preos it's an extension of the protocol that basically deals with the question of what happens if messages are delayed because what we do in this proof of stake is that we explicitly discretize time and and use time intervals these slots and we have a block for each slot and then of course in order for for the chain to work this information of the last block has to propagate the network before the next slot leader has its turn because because otherwise we would get folks automatically because just the people would would think that slot is empty and in real networks you can have delays of messages sometimes you have outages you have stuff like that and Roboros preos tries to extend or does extend the adversary model to include network delays and then if the network becomes becomes less reliable than the adversary strength grows stronger and you have you have less guarantees but you still have guarantees and you can quantify them and that's what we're currently implementing for for the next version of Cardano right so that's that was basically the introduction part to to Cardano the next thing is then how do we go from from actually from a paper that that contains all these these proofs and those cryptographic protocols from something that looks like this where you have text written in in just English language and mathematical formulae into something that looks like this which is executable by machine and actually runs the system and yeah there's quite a lot of gap between that because the paper is as I said it's just written to to be understood by humans and to have a discussion about it by humans and and it it glosses over many details that you that you don't need in order to reason about the protocol but that you would need if you actually run the protocol on a on a on a distributed network of nodes so yeah paper interpretation as I said they they they they are very different things you have the publication that is at a very high level of abstraction because when you talk about those cryptographic protocols you don't want to worry about stuff like database connections or networking details or anything like that so the thing that they they say the paper is they they have a network as some abstract functionality that just gives messages from one computer to to the rest and and that's it but that's not something that you can put in code of course and it's something that that is meant to be understood by humans so it's it's elaborate and it's it's not as precise as a as a programming language there's lots of implicit conventions in the literature and and stuff and and yeah it's meant for a discussion among experts and not for just dull interpretation by machine and it also has has real mathematical proofs of of the security guarantees that they give and on the other hand the code it has to deal with all those those low-level details and that that the cryptographers don't don't want to consider them and that they also don't have to consider it if you want to have a natural running machine then you need to consider those at some point it's written in in in a very formal language so in our case it's Haskell and the question is if you have code can you also somehow transfer those those proofs that you have in the paper to to the actual implementation and the the key thing that that we're going to do is to avoid doing the thing basically in one one big leap where you where you conflate these these things of changing the language and adding the detail and instead go in very small steps because if you if you do small steps then it's easier to make sure that that each of those steps is correct and then by induction if each of the steps is correct and also the whole thing is correct so the first step in that is to just do a translation of the algorithm and the protocol into a very formal language without adding any detail at all staying at the same level of abstraction talking about the same things and but but getting to something that is readable by a machine and where the machine can can can interpret it and can at best even understand the proofs that you have about it and then once you have this precise but still very abstract thing you can add one detail after another you can refine the thing add detail and basically go one step after the other add a storage layer add networking add add multiple things do performance optimizations everything like that but do that in small steps and so steps should be small enough that you can either do proofs that those steps do not spoil your correctness or because proofs are very hard to do and require lots of time and we want to deliver at some point and we have some some business needs of of finishing in a finite amount of time at least to basically test things and do proper reviews of those and have your colleagues accept that that this is that this is correct and also when when you do those small steps you are very explicit in where you make design decisions because there's there's multiple things where when you add detail you have a lot of freedom because if you're at a high level of abstraction all these details aren't there and if you add them you can add them in multiple ways you can you can put an emphasis on performance you can do some optimizations you can you can put an emphasis on on on readability of the code and all these decisions they they are very explicit if you do small steps and as I said along the way if you if you add those those steps you should at every step you should be able to simulate the thing or test it or or both or in fact prove that the refinement doesn't doesn't spoil anything now the first step is translating it into a formal language and the question is what should that language be and if you look at a blockchain then basically what you have is lots of computers that that talk to each other that that perform a distributed calculation of this of this ledger and there is there is a lot of literature on that and the way to formulate this precisely and formally is to have process calculates so those are languages that they that that model distributed systems and they model it in terms of processes that that can be run and that can communicate via channels so you have lots of processes they can do some computations and they can talk to each other by sending messages over channels and then if you have multiple processes you can compose them either by running them in parallel and they're letting talk to each other or you can run them one after the other they can send and receive data and what's what's very nice about these languages is that the people working on this have thought about things like how can we say that two processes are similar or interchangeable and there are notions like observational equivalence where you have two processes that differ but they don't differ from the outside world if they may differ in details but if you just talk to them and look at the messages that they send then then they are interchangeable and you can you can talk about that you can prove that that that different processes are exchangeable in this way and you can also do stuff like equation reasoning because if you have two processes that are interchangeable then you can you can basically do stuff like like manipulate formulae where you have processes and and you can you can have a compositional language where you can talk about the whole system in terms of its components and can look at the components prove things about them and then put them together and that's that's very nice and it's it's the correct thing to to describe these distributed processes this distributed systems with and there's lots of languages lots of formalisms there CCS, CSP, ACP, Pycalculus so lots of lots of papers to read and lots of lots of tools also and and lots of theorems papers and stuff that are useful for for working with those things. We want to eventually use such such a language to describe our blockchain but we want to use it within the programming language that that we're using and yeah so we have to add that to the to the language and ah sorry one step back so the the process calculus that we that we go for is called psi calculus and it's actually it's a it's a family of process calculus so the thing that you have to do there is to specify types for the data terms that those processes can exchange and for for conditions and and assertions and then you have things like a trivial process that does nothing you have processes that can send to a channel you can have processes that read from channels you can have cases where you pick one of several processes depending on some some some some condition and stuff like that you have parallel composition you can wrap you can wrap you can do a process over and over again and stuff like that and there's well-established theory for that and also tooling you can have there's the psi calculus workbench which is a formalism and which is a toolbox for for the Isabel theorem prover and so that's that's what we what we are using to formulate this um uroboros priors protocol right so we have this this language to talk about to talk about these three processes but we want to embed this basically into into a Haskell and that's where where a thing called embedded domain specific languages comes into play and the idea is that you can basically write write any program in any language but it's easier to reason about your program if the language is actually suitable to the domain and if if you do something in a in a certain domain then the idea of domain specific languages is just to create your own languages that that fit this domain and that make it easy to to um to reason about your programs and examples for languages for for specific domains are postscript for describing pages of text or graphics regular expressions for text manipulation sql for databases and the thing with embedded dsl's is that you um that you create the language inside another language and then you can use all the syntax control structures and all of that of the host language and just have your your program itself as a data term within that language and that that all sounds quite abstract and to to fill this with a bit of life there's a very very easy example a very simple example that that's typically used to to um describe this to to to to give an example that's called Hutton's razor which is basically the the the most simple dsl that you can think of and it's just a dsl that has two components it has integers and it has additions and so um maybe uh who's familiar with with haskell syntax who's read any haskell at all that's okay so um this here is a is a data um is a data term a data type a data type definition and it says that this data term called xp has two cases that it can have it can either have a literal um integer or it can have um another case an addition which contains two expressions so this is basically you either have numbers or you have a sum of two numbers and then you can produce terms of that by just using those two constructors add and lit and so this would be then basically one plus two plus three and um so you can you can form basically programs that represent um just additions within that language within that data term the within that data type and a program would be just a term of that type and then the next thing that you can do is to interpret this program and you can do that in multiple ways you could either say okay once I have some term like that I want to evaluate it and for that you would write a function that takes a program in this language xp and produces an integer and the way you would do that is to say okay if I have a literal then it's just the value of that literal and if I have an addition then I evaluate both sides and add them together and um in that way you could evaluate this term and would get the answer six the nice thing about um having such an embedded um domain specific language is that you are not tied to one specific interpretation but you can write multiple interpretations so another thing that you would might want to do is to write a function that takes such a program and outputs the string that corresponds to that program and again you could do that just by um printing an individual integer or by if you have a an addition you would write a parentheses a plus operator and the two numbers and then you could evaluate this this term to to the string so um yeah so so you can you can write a program in that in that language and then you have different you can have different evaluations depending on what you want to do and the idea for having that for the for the for the Psycalculus in Haskell and for for implementing the protocol is that we implement Psycalculus as an embedded DSL in Haskell and then we write the Uroboros prayers protocol itself in this language and then by writing different interpreters for the language we can do stuff like simulating the program by by pretend by looking at what would happen if we would run it and getting a list of log messages basically or we could export it to the syntax of a proof assistant like Isabel or Kock if you want to prove that we we made a step of refinement between two versions of the of the protocol then we would like to prove that they are exchangeable and for that we can just export the programs into Isabel syntax for example or what we could also do and and this is the end goal is to have an interpreter that actually runs the whole thing where we add all the details all the the networking the storage layer and so forth and then the same program that we have that is the basis for the simulations and for the export of the proof assistants will be ultimately what what is actually running on on the nodes and that's that's very nice. How does this look like in practice so this is probably a slide that you you might want to gloss over if you're not familiar with Haskell it's basically again a data type where we have different constructors one for a process that does nothing one for creating a channel one for consuming some input from a channel and getting a new process one for outputting some some data to a channel something for logging and then we'll write we will have different interpreters that that take a list of processes and then either simulate the whole thing and give us a list of log messages or export the whole thing to a to a proof assistant or actually run the whole thing and have the program that's that's running on a node and then the actual thing will have some something more we'll also add channels where everybody can listen to that and we'll allow a process on one node to to have sub processes that that can only communicate to itself and stuff like that but but the simple I mean that the general idea is the same thing as with a simple addition language you have one data type you have different constructors for that data type and each one gives you something from that language constructing new channels communicating over channels stuff like that forking a new process all these things and right so that's that's the the formal language for for basically expressing expressing the the the consensus algorithm the the protocol once you have that you can build this this basically a tower of abstraction where you have the formalized the formalization of the paper at a very abstract level and then you can add lots of details and while building this tower of abstraction we can go from the from the top down which you can't do with ordinary towers the first refinement that we could do is for example that in the paper they just talk about chains and each each node has its own chain and they talk about their chains but in principle what you do is that you send around single blocks and that's already something that that makes the thing more complicated more involved so talking about chains is is easier and it's easier to reason about but what you'll actually need to do is to send single blocks through the network and then add blocks to chains and and stuff like that the next thing is that you need to add persistent storage to the to the individual nodes you need to add networking you can do optimizations with performance and stuff like that and then in the end you end up with production code right so so that's basically various versions of the same protocol having different different levels of detail basically a different granularity more details here as you go down now if you um if you evolve this over time if you do some something with this with this protocol for example you could wait for an epoch and see how the system looks like or you could send some transactions to it or you could have different events that happen to it then you will have two versions of the of this whole tower of of of protocols and they would differ in in their state because they have they time progress here from from left to right so they have have they have had some transformations and the state changed and you can do that at different levels of abstraction you can do that with just regarding the the abstract protocol and you can do that with the actual production code and the nice thing if you have this whole tower of of basically of of versions of the protocol at different levels of abstraction is that you can go from the production code up to the to the to the abstract method by just by just abstracting stuff away by by hiding the details again and that gives you a very nice setup for for testing in that you can write tests where you have an initial state in the production code you evolve it over time and see what the what the final state looks like and then at both ends you can abstract away from from various details and end up somewhere higher up in the tower where stuff is is much simpler and you can do that on both sides and see how would the abstract model have evolved over time and then you make sure that basically what you end up by going from here to here is and then and then to there is the same as you end up with going from here to here to there and that is that's a very nice test because the state transitions that you have here they will be very complicated and they will involve everything in your system they will involve the storage the networking and and and all that and all the and possibly some optimizations and up here it will only be be the paper so that's something that you can that you can reason about and that you can write simple simple stuff about and if you if you test that that going from here to here is the same as going that way then that's that's very nice that's a very nice testing setup right um yeah say again yes yes it's it's it's this is also so the initial step going to the formalized language that's basically from from outside here so you have here that you have the paper and then you you formalize the paper into this formal language and then within that language you can add details by just by just adding refinements to your program and adding stuff that is kept abstract at this level and then um yeah adding adding detail there and so so this is all within the same language and just just having more or less detail does that answer the the question okay good right so the last part of my talk is about modeling performance because um what we um um what we what we need in this in these proof of stake protocols is is to have a good handle about the the performance of the whole system because as I said you have this this this this slot length where you need to have blocks propagating through the whole network and so you need to have you need to have a very clear picture of how performant your your system is in order to set this this slot length and to set other parameters that that basically behave how difficult it is for for the nodes to to verify a block and to send it around and so there's various parameters that you uh that you can tune and in order to tune them efficiently to get a good throughput in terms of transaction rate and to have the system run stably you need to know how how well it performs and um what we did before the launch is to basically set up a benchmarking environment where we where we have nodes running on different continents and we we try to put pressure on them by sending lots of transactions to them and then seeing okay can they keep up and how can we tune these parameters where do we have a safety margin and so on but um what would really be nice if we um if we could have a handle not only from from experimenting but also from theory if we could basically get a prediction how well should this code run because if you do a benchmarks then you you get some numbers and you see okay this is the time that it takes for a block to propagate through the network but you don't really understand why that is the case or neither do you understand whether that is actually good and what you should expect if the code were perfect or whether you you have some room for improvement so what we want to do in these in these um in these um languages is to also include a notion of performance in it and of timeliness and then we can answer stuff from the protocol itself like how long does it take does it take for transactions to be recorded in the in the system how long does it take for a new node to join the network and get knowledge of the blockchain and is this this critical thing that blocks propagate through the whole network how realistic is that assumption given a certain slot length and also what kind of resources do you need to actually run a node and um the the language that we use for speaking about that is um to look at something that's called impairment of quality or delta q so um this diagram here is basically on the x-axis you have time and um on the y-axis you have the probability that by a certain time some event will have occurred and in in perfect systems you would just have a have a line that approaches one at some point if if the if the event that you are waiting for must occur after some time then this would reach one but since a real world system always can fail this will not approach one but typically will will saturate at some at some at some lower level and then the difference to the one will be your your chance of failure if you if you wait for an arbitrary amount of time and um so that's called what's in that's what's called an improper cumulative distribution function so at at each point in time you have some some probability for the event having occurred by that time and um right so that's something that we can model in in Haskell in our language and basically how we model that is um by having this delta q be a function that takes the state of a random number generator and then produces a pair of either a number of seconds that it took the event to to occur or nothing if it didn't occur and a new state of a random number generator and then you can express some some simple um delta q expressions like an event that happens exactly after some number of seconds or something that happens immediately or never or something that happens within some some interval of time and you can also combine these these basically these simple um delta q expressions so if you have something where you have an event that will occur after some time and then after that something will occur with a with a certain probability within some interval then you can you can add those things together and and compose them one after the other or you could also um wait for for the first one to occur and you can you can model this relatively nicely and um and then you can perform simulations about that and um just to give you an example I'll show you something that that last it actually um a simulation um where you have a ring of nodes and you pass a message from one node all across the whole ring back to itself and um with each with each step the message has some some distribution for delay and some chance of failure and then of course what happens is that if you just send the message once and wait for it occurring then at each step it it can fail so the the chance of failure basically will will add up and um then there's different scenarios that you can that you can observe you could either say okay I just send it and wait for it to to to reach the endpoint again or I send it and if I notice that it didn't reach that point by some time I resend it or if I if I notice that it didn't make the first hop I resend it immediately and then you get this this nice graph you get here below that that's basically the curve for just sending it once and hoping that it will arrive eventually and you see that um the the probability for it arriving is rather low and that's just because the you you multiply the chance of it arriving eventually each time you make a hop and so you get an you get an exponential decrease of of actually um of reaching the the your goal the the next best thing is to just resend it after you make sure that it didn't arrive at the at the destination at all and then you basically have some uh a chance that it arrives on the first go and then after you notice that it didn't uh make it you send it again and you get the same chance again and you add it up and then after some point you you approach nearly one and then the the best thing that you can do is to resend it immediately if it didn't make a single hop and then you basically get this this smooth curve that approaches the one rather rather fast and um what we can then do once we once we have these simulations that is that we can include this into in this domain specific language that i showed you earlier so um whenever we have communications between two processes when you when we send a message or we receive a message then we can add an annotation for this delta q to the message itself or to the to the channel and um then we can when we do simulations of that we can actually um not only do a simulation of what will the thing do but also about how fast will it do that and what are the chances of it failing and that's that's um that's rather nice because then we have a handle i mean we we have to get some input and saying okay we we think that a message from here to there takes about that amount of time and has that chance of failing but if we then model that into our system we will have actually in our simulations we will get numbers for the overall system which we wouldn't have otherwise and then when we compare that to benchmarks we have a baseline of saying okay if if we deviate from that prediction then either our assumptions of the individual messages was wrong or we have some deficiency in our code that we should fix and um these annotations there they are um we can use them when we do simulations and we can just discard them when we do stuff like proving proving stuff about just just the functionality and not not see the chance of failure or the the um the speed of the system the performance of the system or also when when actually running the system then we don't want to add those those delta q things um the next thing that we can do with this formalism is not only not only can we simulate it but we can also reason about it algebraically so um when you have two two of those terms in delta q then you can compose them together um for example if you have two processes and you run them in parallel and just wait for the first one to finish and you want to and you wait for the last one to finish so you want to the the event that you wait for is that both of those events have finished then at any point here you will say that um both of them have finished if you are at or below both of those lines so what you need to do is take take the minimum of those two curves and then you have from from two from from basically from two events that you can um have in your in your delta q you have the combined event of waiting for both of them just by taking the minimum function of those two and in a similar way if you wait for just one of them and your content if if one of those events happened then you take the maximum and you can also do stuff like a parallel composition a sequential composition and that's that's basically convolution so you start basically having a non-zero chance of both having occurred by by adding by by adding at at each point by by I mean what you have to do mathematically is convolute those two those two lines and you see that this starts basically after after adding the times that it takes both to get a non-zero probability of finishing and then once you are here where both of them are okay have the time to to um to reach basically the maximum then uh then you get here saturation as well and since we have um since we can calculate from those individual terms how they how they behave we can do this algebraically we can do the the next thing and we can basically embed another domain specific language for this delta q where we have um terms for just either something that happens exactly after n seconds for some variable that's free or for doing sequential composition for waiting for one of two processes for multiple processes for waiting for one of two processes to occur with some with some random choice or by doing different things depending on what what event happens first and with this we can we can not only do simulations but we can also derive basically expressions that tell us how that tell us how the overall performance of our system is in terms of variables that express how individual um how how basically the the um irreducible components of our system behave how how long it takes a message from from here to here from one aws center to the next and with that we can we can basically identify where bottlenecks are if you if we see that some variable has a large impact on the overall um delta q then we can we can say okay this is this is what we'll have to optimize we can we can identify regions in the code where we actually um should concentrate our efforts on non-optimizing and this is having both of these things the overall simulation which just gives you numbers right away and then also having algebraic um expressions which might be difficult to to interpret and to to to get to get to overall numbers but but can can tell you all these these details like which part of the code is it that's actually holding me back and that's that's very valuable and then we can like like we did with these with these uh simulation kind of expressions before we can also embed those annotations for those um symbolic delta qs into our um process calculus and then we can get predictions for how our system will will um will actually perform in terms of its individual components just just to summarize the these cryptocurrencies they carry large values and so um we think that it's that it's proper to to do to do things with with with a large degree of assurance so we have we have researchers who actually prove things about the protocols and prove that they are secure but then we also need to make sure that those proofs don't get lost in translations and that's because blockchains are used for cryptocurrencies where there's lots of money there's also proposals for for having critical infrastructure like lend deeds or something like that on there and so we we need to have this we we need to have systems that are fit for purpose where where we can go to base for for instance to an insurance and tell them okay this is the system we're using and you have to risk this and these are the models that we're using these are proofs that this is secure and and stuff like that and um yeah so so the way that we do this is to to make sure that we don't take too large steps by basically going from this this abstract thing in a in a human language to this to this very detailed thing that is interpretable by a machine but we take small steps translating the thing at the same level of restriction and then going step by step until we have something that's actually executable and can be run in production and also because in especially in these proof of stake systems you you need to have an eye on performance because if you if you have if your performance is not as it should be then you might get out of sync and you could get folks because just the next dot leader doesn't doesn't see the the previous block in time so that's why it's also important to design the systems for performance upfront if you want to look at all this in more detail the repository that that we use for that is is open on github and uh yeah i'd like to thank you all for the attention thank you organizers for the invitation thanks