New Ethereum talks, every Monday. The week's conference uploads by event, in your inbox.

Beyond the Ledger: JAM and the Future of Scalable Decentralized Computing

ETHBerlinThu, Jun 19, 2025, 12:21 PM · 1:09:17

Blockchain tech can be more than just a ledger: it can be a scalable global computing network, moving away from transaction-centric blockchain design into a decentralised computer one, changing usage patterns, development patterns and tooling. The Join-Accumulate Machine (JAM) is a new protocol aiming to make the usage of blockchain core radically un-opinionated, and to enhance the scalability and efficiency of blockchain networks.

Transcript

Thank you, thank you, cheers, thanks, nice to be back in a different place though, right? A bit more full on. Right, I've got like kind of three broad things to talk about and I'll try and do what I don't usually do which is leave time at the end for questions. Right, what do you want to show on it? The screen I guess, mirror, alright, good.

So I'm going to jump straight in. If you don't know, I've been, actually my talk last year at Protocol Berg was discussing the protocol I'm working on, Jam, and now we've done a lot more work on the protocol. We have some numbers, we have some further insights and I'm going to basically go over those numbers and insights and try and give you a demo of it towards the end. The first thing I want to cover is the security mechanism for Jam. So if you're not familiar with Jam, it's a blockchain and its broad direction is to take a lot of the work that we did for Polkadot and combine it with a lot of the, or with some of the elements of Ethereum, particularly having a single coherent object environment.

And one of the things that we really nailed with Polkadot was getting a lot of computation through that was very secure. So we basically scaled our base of security really nicely. Now the sort of, the product that we used this scaling mechanism for was probably a is awesome. And this underlying tech is what's being leveraged with Jam. And I want to just like give you an idea of how this underlying tech works because we've seen with scaling security in protocols, we've seen a lot of work, a lot of hype, a lot of tech that we've seen arrive over the last five or 10 years, snarks and starks.

And one thing that we've found doing our own empirical analysis of this technology is that it's shitty for scaling security, which is why we don't use it for that. We use it for other stuff, but not scaling security. So Jam, and for what it's worth, Polkadot's security mechanism is based on ELLs. This is a protocol that was devised at the Web3 Foundation. And you probably understand parts of it quite easily because parts of it are kind of, say, take some inspiration from what Ethereum would call optimistic roll-ups.

But the basic problem it's trying to solve is this everyone computes or verifies everything approach to blockchain security, to giving security to computation, giving a guarantee that the computation that has been done is indeed that these are the correct results. And, of course, that there won't be any alteration in the inputs, also known as finality. And the way that we scale security is perhaps not super surprising. We use divide and conquer, something that's used all over the place in computer science. In this case, we take our set of validators, say a thousand of them, and we split up the work that we want to ensure is being done correctly between these nodes, say three nodes per piece of work.

And then each of these bits of work come with a bundle together with a bunch of information that proves or can prove statelessly that the work was done correctly. And probably this is already starting to sound kind of familiar. And once we agree that each of these bundles are definitely available to any additional validator that wants to check it, then we can agree that this work is ready to be checked and after checking, ready to be finalized. And this is what we call auditing. And the way that this protocol works, the clever bit of it, is how the auditing, the rules for when audits happen and who does them.

These are very subtle rules, and they have to be designed very carefully so that it's not possible for some attacker to get something past the auditing stage without an honest party, at least one honest party, being able to audit it with a reasonable expectation that if they audit it and it turns out to be invalid, that they broadcast it to the other honest parties. And we have various, like the ELVS protocol comes with the main paper, comes with various base assumptions in terms of honest parties and connectivity and all the rest of it that you would typically find in consensus protocols. And the nice thing is that the paper ultimately proves that under these rules, the likelihood of a malicious party sort of getting away given these assumptions is approximately the same as if the whole network itself were checking these things, these reports. One of the sort of ways, one of the little tricks that the protocol uses is announcing before validating. And this particular trick is an important one.

And it's there in order to ensure that if a validator gets dosed, basically, if they get prevented, maybe there's a bug in the client, and if it is known that this validator is going to do an audit, they could potentially be dosed, taken down, and maybe the audit is going to pass, maybe the report is going to pass without being properly audited by an honest party. Or maybe they do audit it and they get taken down afterwards or immediately on auditing in order to prevent the negative judgment from making its way to other nodes. Either way, we want to avoid this possibility. And so what we do is we require auditors not only to self-select based on a verifiable random function, but also to announce before they do anything else. And once they announce, it's almost like a contract.

Any other auditors, any other validators that see this announcement and don't later see a positive judgment, it sets up the default. The default is, make audits more likely for this package. Basically, find other validators that will audit in the place of this missing report, of this missing judgment, for fear that there's some sort of DOS attack going on. And because this rule and a few other subtle rules, we can make a proof that this gives security approximately in line with just having all validators audit everything. And this allows us to scale the security that we provide for our work that happens on-chain.

Now if we compare this to the assumed alternative, which is basically having some affected GPU supercluster, whether it's located in one particular space or distributed around a bunch of different nodes, if we compare the actual cost between these two approaches, we find that this crypto-economic means of scaling is about 2 million times cheaper than an equivalent ZK proof-based approach. Not to mention latency and centralization that the ZK proof-based approach would add. So for comparison, ELLs has a latency of basically one block, about 6 to 10 seconds. Good luck making a proof of some serious computation, like 6 seconds worth of some high-efficiency VM in that amount of time, and for anywhere close to the cost profile. And if you're interested in the numbers, here's some numbers from our empirical investigations.

Basically, we're looking at around... We can do, under ELLs, around almost 100 million, well, 100 billion gas, Ethereum gas, EVM equivalent gas per US dollar. And you can compare that to what it currently costs on two of the bigger ZK protocols, coming to around 44,000 gas per dollar, with the massive amounts of latency and finality. So this is why we're really not that bullish on using ZK methods for scaling computation specifically. Right, that's the first part of my talk.

The second part of my talk is a different thing, because I was on a plane when I authored it, so I couldn't be online. And hopefully, I've never used this app before, but hopefully, I can make it big. View. Play. Play, there we go.

Now, this is another aspect of Jam that we've been investigating, or another aspect of building a blockchain, building a smart contract, general purpose computation blockchain, that we've been investigating. Consensus VMs, basically. You know about consensus VMs, almost certainly. You've probably heard of, I mean, you know about EVM. WASM is also used as a consensus layer for a virtual machine, as an instruction set architecture.

There are others. Many networks have their own. And we have one of them that's sort of ours, which is the PVM that's a derivative of the RISC-V instruction set architecture. And they tend to be slow, these things, right, compared to like native execution. And it's important to sort of, if we're going to design these things better, like better protocols, with better consensus VMs that they're based, we need to understand how they become slow in order to understand how to make them faster.

And we'll assume for now that we want them faster. There are arguments, I mean, I've heard an argument that's like, ah, they don't need to be so fast. All people are ever going to do is like send a balance to another smart contract. Or another one, slightly better argument is, ah, if there's like a really difficult piece of computation, then we'll just introduce a precompile. But the thing is, precompiles require basically governance to be introduced, to introduce them.

And this is hard. And you'd also have to work out, you know, at what point to introduce a precompile and how many you introduce, given that once you've introduced it, you can't take it away. And if there's some particular computation that you want to do, but that computation ends up being slightly different in the future, and you're precompiled as the first thing but not the second thing, then you've got a big problem. You basically have to have two precompiles that do almost the same thing. It's not a great way of proceeding when our intention is to build general purpose platforms.

So, let's start the basics. Why are consensus VMs slow? Well, they have three particular characteristics, or we require three particular characteristics in consensus VMs. And these are kind of slightly weird characteristics. They're not characteristics that you would typically have found in VMs pre-2014.

And let's list these three things. So, firstly, it has to be deterministic, right? It has to be objective and deterministic. So, it's got to do the same thing for any given program plus input, right? Now, this seems on the face of it quite a normal thing to expect.

But it turns out, like, not so much. Particularly for physical hardware that will tend to have a single vendor, they are not necessarily going to define everything perfectly from a mathematical point of view. Now, they might want to, but there will be instances where the hardware does something different and they kind of just shrug their shoulders and say, well, we're not going to change the definition. So, you just have to live with the fact that the hardware, under these very particular circumstances, doesn't quite do what we expect. And this is fine in a fuzzy world where there are lots of software writers and they can just basically manage these very, very unlikely circumstances by turning it off and turning it on again, basically.

But it's not so great when we need, we have a bunch of nodes that we're going to, like, slash or somehow punish if they don't come to the same answer for any given set of inputs and programs. Now, point two, we need to be able to limit the work done. This is also a tricky thing. We need to be able to limit it also under the same circumstances so that we either limit it or we don't limit it. Either this work has taken too long or this work didn't take too long.

But we need to be able to easily hold this condition in consensus and if it does take too long, interrupt it and then basically don't sort of do anything. This is similar to the third requirement, which is a much more smart contract-oriented requirement, which is that we need to ensure that we agree on how much work was done. Now, this is, in Ethereum terminology, this would be the amount of gas that is used, right? Or the gas limit. This is a hard one.

Why is it hard? Well, because not only do we have to agree on how much work was done, and you'll find what's called metering in non-consensus VMs. For example, Wasm, there'll be a number of Wasm implementations that will have metering. That's not so much the problem. The problem is that we need to, this metering has to be close, has to be close in terms of modeling to the amount of real world time taken for this computation.

So we might agree that some particular program took one million steps to execute and this is information that Wasm will give you if you turn on metering in one of the compliant implementations. But we don't know how much, say, an AMD Threadripper 5 GHz will core, assuming that there isn't some crazy memory contention or the rest of it, will take to execute those one million steps. It's not in any way linear, that ratio. Different instructions take different amounts of time and there can be all sorts of circumstantial, situational circumstances to change that, to change the amount of execution time. Now this is also important to understand.

This isn't about trying to place a maximum bound on the execution time of a program plus input. It's really on a program trace. So it's not that we're trying to get away with solving the whole thing problem here. We totally expect that we will have to execute the program and that's fine. But what we want to do is model for any given program trace, like an execution trace, like the specific instructions executed along with the state of the machine and everything of every given instruction.

Well, we want to model how much time that takes without actually having to name a specific CPU piece of silicon, my laptop, and say, well, that will do it and we'll have some atomic clock next to it and measure that. Yeah? Because that's obviously not very practical in a decentralized network. But in a sort of decentralized sense, like in a centralized sense, that's what we're trying to do, right? We have a sort of conceptual computer that's modeled, that's sort of manifested by this decentralized network and we want a definite answer to how much time did this non-physical machine take to execute.

I mean, it's kind of a mad thing to imagine, but it is literally what we're trying to do here. Now, how do these requirements slow us down compared to, say, native execution? Well, the first thing is that we're not using a native ISA. Now, we could use a native ISA. We could just say, right, we're going to use x64.

Screw it, or x86. The thing is, these come with a lot of extra crap that we don't really need and there may be some very finicky, difficult ambiguities or worse, non-ambiguities, but hardware may not implement these standards entirely correctly and this results in sort of difficult mapping from the ISA to native. Now, the further away from the native hardware that we get, probably, it seems reasonable to assume, that the harder it is to sort of get that native level speed. Assuming that we want the same generality, right? If we're only trying to do one thing, like, I don't know, send a transaction or compute a Fourier transform, then, you know, it's fine and we just make a totally optimal version of that and then, bam, we don't need, it doesn't, you know, our sort of instruction set, which is presumably just FFT with the input, doesn't need to be anything like the native hardware on which it's running because it's only got to do one thing.

But if we want something that's like Turing complete, we want something that's actually general, then it's presumably going to be a lot faster to make it closer to the actual native ISA that this thing is going to be running on. And we already, we can see this. Like, it's a theory, but we can demonstrate this. We have evidence. And the next thing that's hard is that the wall clock execution time is not easily predictable.

Now, it probably used to be quite easily predictable, like, long ago in the 486 era and may even still be relatively easily predictable on some types of hardware now, simple hardware, basically. But if we want this stuff to run fast on modern CPUs, on like, you know, server or consumer grade CPUs that we would find in this laptop or that laptop or some server somewhere, then things become a lot harder. And what we're left with is kind of two kind of paths for doing this. One of them is, they're kind of interesting paths philosophically because they trade off accuracy for precision. Two words that often a lot of people sort of confuse or mix up or think is synonymous.

They're not synonymous. And this is, this subtlety is actually here. One of them is a theoretical estimation, right? This is like gas metering. This is where we say, right, it did this execute, it started with this input, it did this instruction, this instruction, this instruction, and we think it took 15 gas, which equates to 15 nanoseconds, right?

Very objective, totally precise, but unfortunately wildly inaccurate for most, like, for basically any hardware, any real world hardware. The alternative is to get something that's much more accurate, i.e. closer to reality, but unfortunately subjective. And this is like, run it on your own machine.

Run it on the machine that is, run it on standard hardware, get a number. It's probably going to be close to the number that anyone else gets when they run it on their own version of the standard hardware. It won't be exactly the same, but as long as you take proper precautions, it shouldn't be too far off. And so we have this precise but inaccurate versus accurate but imprecise. And it's not always, like, it's not so easy to know sort of which way to go down.

For what it's worth, Polkadot, at the moment, the relay chain of Polkadot, not the smart contract parachains, but the relay chain of Polkadot, uses the second method, whereas, you know, most smart contracts, I think all smart contract chains pretty much, use the first method. And that's kind of how Polkadot gets a lot more processing done. But it does mean that the, at some, there is, in some sense, less granularity, right? There is less granularity. You kind of can't combine different users of the computational resource in the same invocation, essentially.

That's what it comes down to. So it's interesting, you know, we're interested to know how bad this really is. So one of the, there are a few different ways that modern CPUs speed things up and do so in some opaque way that's not actually got anything to do with the instruction. Caching is a really big, obvious one, but there are a few others, branch prediction, pipelining, and so on. There are a lot of tricks that they use.

And these tricks are very much, well, firstly, they're CPU vendor-specific. They might even be CPU-based. They might even be CPU model-specific. And they are designed to be opaque. They're designed so that the software can't really tell what's going on.

Now, there's probably some cunning trade-off between making the consensus-level instruction set architecture be kind of closer to native and further from typical usage. We would assume that the closer it is to native, the faster we can make it go. But the further it is away from typical usage, the harder the cost model, it turns out. But assuming that we want long-term generality, we kind of have to, we have to be quite close to native because we need the flexibility. We can't just assume that we know ahead of time precisely which operations the user, or which compound operations, right, FFTs or, I don't know, matrix multiplications or whatever the user wants to do.

All right, so let's take it to the numbers. So we come up with a couple of experiments. And we have, at the bottom there, we have our sort of platform that we're running computation on. We run it on a native x64 platform, some standard hardware. We also run it under our Poker VM, our interpreter.

We actually have a poker that we have both an interpreter, which sort of goes through and interprets every instruction one at a time. You know the thing. And also a recompiler, which basically takes the whole program code and recompiles it from the instruction set of Poker VM, PVM, into native x64. And then runs it as an x64 program. A bit like, you know, JVM with the JIT.

Except this isn't JIT, it's ahead of time. So it actually goes through the whole thing and streams out a native program and then runs that. And then on top of here, on top of this platform, whether it's native, an interpreter, or a recompiler, we run something. Something useful, something vaguely useful. So one of them is like a SHA-1 hash, 100 kilobytes of data.

Another one is this mad interpreter inception thing where we actually run a RISC-V interpreter. And then inside of the RISC-V interpreter, a 6502 interpreter. Actually a whole NES emulator, but a big part of that is the 6502 CPU. And then on top of that, basically one of these hardware test ROMs that just goes through and tests all the hardware. And the idea of this is to make something that isn't particularly well-suited to anything, right?

It's just... It's a largely unopinionated, or the intention anyway, is a largely unopinionated amount of computation that's probably going to be quite pessimistic for our GAS model simply because it involves a lot of arbitrary memory reads. And we found that, it turns out, arbitrary memory reads are hard. So we wanted something that was kind of pretty hard to do. We also wanted something that we could recompile with Solidity.

And making a RISC-V interpreter, turns out it's actually quite easy to make a RISC-V interpreter in Solidity, compile it to EVM. And this gave us a really nice way of having pretty hardcore compute, but comparing it across the board. Now, for the hashing, we used like a hand-optimized assembly version of an EVM SHA-1 hasher. And we compared this to just compiling the standard SHA-1 crate in RISC to RISC-I. Sorry, to either NativeX64 or PVM.

So again, we had, we tried to give, we tried to make things hard for ourselves. And we tried to give EVM as good a break as it could get. With also, for example, we switched off the bounds checking for the RISC-V interpreter running on EVM in order to try to, you know, give it as, as I say, as good a break as possible. Now, we have three gas cost models. Because at the end of the day, we can, it's all very well metering what instructions pass.

And we can even meet the different instructions differently. A multiply or a divide probably takes more time than an addition. But for memory instructions, it's massively dependent on whether the thing you want to load from memory is in the cache or not. And broadly speaking, you've got four possibilities with modern hardware. It's either going to be in L1, it's going to be in L2, it's going to be in L3, or it's not going to be in any of them.

And you have to go to main memory. And if you choose the right CPU, you'll get about one megabyte of L2. Yeah. That's about as big as it gets on the consumer side, but still. About one megabyte of L2 per core.

L3, it can go into the, you know, 10 plus megabytes. And then after that, it's like main memory. And what we wanted to do was, was basically take the ratio of gas to actual wall clock execution time, depending on whether we assume it will be, we didn't bother assuming it's an L1 hit, because it's trivial to write code that can prevent L1 hits, right? It's trivial to write malicious code. But we did want to compare it for L2 hits, L3 hits, and an L3 miss.

And we also wanted to compare the difference between recompilation onto native, and just interpretation on native, and just running it straight to native, like compiling to native directly, and running it as native. And these are the numbers. So, basically, running as native gets us, actually, I think this number is slightly different on a, yes, that should be, instead of 04052, and instead of 014, we managed to get that down to 0075. But yeah, so, it's not too far off after we managed to, if you've got the right code running. The native is about half as fast as recompilation.

It's actually, recompilation is a little bit better in terms of ratio. Interpreter, quite a lot slower. And then, depending on how we, our estimation, if we limit it to, if we make an assumption that we will always hit the L2 cache, which can be engineered, can probably be engineered, despite running potentially malicious code. Like, it can probably be engineered, by a combination of limiting the amount of accessible memory, and making, using a memory manager that basically randomizes things on each of the different nodes, so that it's impossible to predict where two different memory pages are gonna be in physical RAM. Yeah, but anyway, this is sort of CPU stuff.

But the point is that it's not unreasonable to expect that we can guarantee L2 misses under circumstances that are still usable. For programs that need more memory or whatever, then that would be the L3 hit, would be the number to take, and then for programs that just need a gigabyte, then it's RAM. That's the interpreter inception, the hashing, the SHA-1 hash. So, similar, right, similar kind of numbers. A bit smaller, about a thousand times smaller.

So how do we get these numbers as small as possible? Because obviously, we want to make our estimations be as close... to wall clock reality time, yeah, as possible. The close, they're never gonna be lower than, or they should never be lower than wall clock reality time because that would imply that we are effectively giving more work than the network could possibly do. But they should be as close as possible to it.

And at the moment, there may be an order of magnitude, one to two orders of magnitude off. Assuming that we recompile. So how do we get it closer? Well, one of them, as I mentioned, is to make some assumptions on memory usage. Basically, make some assumptions that the L2 cache is always gonna get hit.

And the way that you do this, in our, under our sort of experiments, and we're fairly confident that this is a viable strategy, is to limit the amount of memory available and do some cunning page mapping magic, ensuring that they are at unpredictable places in physical memory, and therefore, that code, that guest code that's running cannot know which bytes it should be hitting in order to cause collisions on cache lines. So, but there's another thing that we can do. Economically sound augmented metering is what I've very quickly named it. And this helps us make up that gap a lot further. Essentially, what we want to do is apply a metering factor, right?

So we want to say, typically, non-malicious code is not going to run at the speed that we assume malicious, this is kind of assuming it's malicious, yeah? And normal code, most of the time, isn't gonna be malicious. We cannot assume that it's not malicious as long as it's, as long as anyone can run any code by paying some baseline amount. But what if they didn't just pay a baseline amount? What if they put some sort of stake in the system?

Such that they lost their stake if the code turned out to be maliciously engineered and take a lot longer than the lower estimates, the lower end, the top two sort of, well, the second line down, basically. And this becomes like an economic answer to the problem. Essentially, we keep our objectiveness because we have an objective ratio that we arrive at through economic means, and we have an objective gas metering system that we arrive at through purely computational means. And we combine them together to get a final objective time. Time.

And this makes up for the fact that we can't get close enough in a purely computational fashion. And this is not unexpected. Hardware, CPU hardware, is complicated AF. Pretending that we can write software that can understand what the CPU is doing under the hood and come up with a number that reflects the time that it will take or that it has taken is unrealistic. And therefore, our only reasonable course of action is to move into the economic domain where we can reasonably believe that if someone hasn't written code specifically to break our gas metering system, then they can probably be sure it's gonna be not far off the average expected time.

And if they care, they can measure it themselves under the input or class of inputs that they expect and become more confident. So we need two things, basically. We need a means of disincentivizing malicious behavior, disincentivizing the engineering of programs that take longer than our gas metering plus ratio would suggest, and the means of working out what ratios will ultimately be able to be considered valid under consensus. So we have to get some agreement on what ratio is valid for any given program execution. Now, it's easy enough to form a disincentive, right?

You take a fake and you just say you will slash it if we agree that the program took too long to execute. But how do we decide that it took too long to execute? And furthermore, given that we have a method for deciding, how do we make sure that whoever's gonna be faking can be confident in that answer, in that solution, in that decision? Want to make sure that the judges are not gonna be biased against you if you're putting some of your own money on the line. So basically, it comes down to three parts.

Subjective measurement, which is where the stator themselves actually measures how long it takes for them on their instance of the standard hardware. Statistical consolidation, where those judges, the validators, in essence, measure how long it takes on each of their instances of the standard hardware. And then statistical consolidation of that into a single value and thresholding. And in principle, it doesn't need to be consolidated into a single value. It could be consolidated into some sort of distribution and thresholding applied to that.

And then we come up with basically a confidence bound as to how likely it was that the ratio was intentionally breached. And if it was intentionally, if it was very likely it was intentionally breached, basically because everyone agrees that the real ratio is far worse than the state ratio, then we slash more. And if it's not particularly obvious it was intentionally breached, but it was probably breached a bit, then we slash less. Now, this mechanism in a lesser sort of imagining is already practically deployed and has been deployed for years in Polkadot. And this would represent a slightly more sophisticated re-imagining of it that would give one very particularly useful thing, which is objectivity over the amount of gas used.

And this is because we have the linear relationship now, because we can take our ratio, which we know is gonna be found because of this incentive structure, and our gas metering, which we know is objective anyway, and combine the two. In Polkadot we can't do that. So let's compare, let's see what this gains us. Let's compare it to a couple of implementations of Ethereum nodes and EVM. So we have a couple of implementations there.

And we're comparing this to our PVM, potentially our Jam implementation, but our Poker VM implementation for PVM. Now, this is for the interpreter inception. There are similar numbers for hashing. So the native wall clock time is the amount of time that it took for this to run when it was compiled to native, right? So we took our RISC-V interpreter, compiled that to native, ran our MIPS, sorry, not MIPS, our 6502 interpreter, our NES emulator on top of that, like within that as a guest program, and then we ran the NES test ROM inside of that as a guest program.

And we came out, we ran it for a frame or two, a few frames, and we came out with this. It took half a second to execute. Okay, now we move into the consensus VMs. So we, instead of compiling our RISC-V interpreter to native and running that with the guest, with the guest of the guest, we compile it to, we make a RISC-V implementation, portable, it's ported to Solidity, and compile it into EVM. And we run it on one of the two Ethereum EVM.

Environments, implementations. Now, they both obviously reported the same gas taken, so fine. It's not that relevant at this point because it doesn't obviously correspond to any particular time taken. I mean, once it did, when we were figuring it all out in 2015, trying to work out how much gas represented, you know, a second of computation, but it doesn't really make any sense anymore. And then we also checked to see how long it took, like wall clock time, to execute the same workload.

So what took 0.5 seconds, 0.52 natively, took 654 seconds when ported, and ported reasonably well, mind, to Solidity, not like some dodgy, highly pessimistic port, but like did our best to actually make it run fast. And 102 seconds on, how do you pronounce that, ETH1? ETHONE?

And then if we work it through, like the amounts of blocks that this would take to actually do this workload on an Ethereum chain, with similar parameters to the Ethereum L1, then it would take about 4,500 blocks, which, again, with similar parameters to ETH L1, will take about 55,500 seconds. The slowdown, therefore, so that it could be attributable to the change in ISA, the change in machine spec, is about 200x for ETH1, ETHONE, and 12,500x for GET. So GET is quite a lot slower, right? It introduced a much greater slowdown, presumably because its EVM implementation isn't as fast. The amount of slowdown we can attribute specifically to the protocol, so given an implementation, an EVM implementation's speed of execution for this workload, how much longer does it take the protocol to get through the workload?

Well, GET does better on this, because, of course, it's slowed down a lot more at the ISA stage. Its EVM just basically runs slower, so it doesn't seem as bad that it takes longer for Ethereum to actually process it on-chain. And that can be attributed to about 85x for GET and about 540x for ETHONE. And then if you multiply these together, you end up with the same figure, the total slowdown, which is about 100,000. So it takes about 100,000x longer to do computation on Ethereum than it does to do the same computation natively.

So let's compare this to PVM and see how much better we can get. So, again, the native is the same. It doesn't make any difference here. Now, we have GAS. Now, the GAS in PVM is specified as being the maximum worst-case time taken for execution, yeah?

So the maximum time taken, maximum worst-case. Worst-case time, maximum time for execution. In this case, POKERVM alone, without this additional sound or augmented metering, is 18.7, right? This assumes an L2 hit.

So it takes, whatever that works out as, 35x-ish as much time, or it's 35x worse, our objective, that our objective estimation is, compared to native. Now, how long did it actually take to execute? 0.8 seconds, right? So that's not far off native, like really quite close to native.

Fairly impressive, we would say. But unfortunately, this proximity to native is only half of the solution. We need to ensure that worst-case, we can predict, our worst-case estimation is also close to native. And in this case, it's hard. So our effective VM slowdown from this is, oh, that should not say, oh no, yeah, our effective VM slowdown for this is one and a half, right?

Because our VM takes about one and a half x longer than running it natively. This is pretty good, right? This is pretty good. But how does this work in terms of protocol when the gas model kicks in and the block limits kick in? Now, for block limits, it's actually pretty good because in Jam, all the work is done essentially asynchronously by the worker nodes, by the sort of validator nodes, and therefore, the amount of work that validators can sort of get through is the same as pretty much like, is the same as the wall clock time, as long as the gas mechanism is sound, right?

So it has to be sound. But because it's sound, it can be the same. We don't need to account for a bunch of the other stuff that will result in most chains having lots of space and sort of doing a lot less compute, even in terms of perfect gas timing because all of the Jam work is sort of done asynchronously, pipelined. There's a lot of sort of optimizations there. So let's look at the protocol.

Let's look at the gas time. So it's, our gas time is around 18.7. So we, our sort of best estimation that is found, right, that is definitely not attackable, is secure, is 18.7.

In reality, I only took 0.5, but our best secure guess is 18.7. And therefore, that's where we get the bulk of our protocol slowdown from. In fact, there's a little bit more than that because our VM did take longer than native, but only a little bit longer than native.

So it ends up being, for the protocol slowdown portion, only about 23x. And we end up with a total slowdown of 36x for the sort of full, after all is considered. Now, if we introduce this sort of economic mechanism for bringing that ratio down, which assumes additional stake, right? So there's like, it's probably the person who is uploading the code is going to be somewhat, or providing the inputs, is going to be somewhat equivocal on how much state they wanna play, like how much they wanna bet the ratio is better. But in principle, this can be reduced to a very, very small factor slowdown.

In principle, two, two and a half x slowdown, which would be pretty good. This would allow for basically two and a half x native, or whatever, 40%, 35, 40% native speed. The numbers for the hashing are a little different, but not too far off. And we see sort of similar, hashing is actually a bit of a harder task, it turns out. So for the EVM sort of Ethereum side, it's more like 300,000.

And for the PVM side, the best case is closer to four and a half x. Good, that is the consensus customizations part. Now I'm gonna skip back to the other bit, the other slide show. Right, I wanna talk a little bit about Core VM. How much time do I have?

Not so much. Right, I'm gonna really go through this fast, because I wanna. So, Jam is progressing, we have tooling. Here's lots of screenshots of tooling. There's like, Jam breaks down into having two bits of logic for its smart contract, if you like.

One of them is a really fast preprocessor that we call refining, and the other one is a still quite fast in-consensus processor called accumulation. Basically, we do lots of refining in parallel, high performance, every block, and then all of that comes together, kind of fan in, and gets all combined as needed in accumulate. Good. Core VM is a means of using this. How does it use this?

Basically, it allows, in the refined stage, which is this very high performance, but largely stateless stage, it allows a virtual machine instance, basically a guest instance of a very regular virtual machine, PVM. So, if you're not familiar with PVM, you're probably not, it's very different to EVM in that it's not stack-based, it's register-based, it has regular memory, 32-bit addressable, and it's metered and it's fast, like all I just sort of mentioned. You can compile regular code to it, right? So, it turns out that because it's RISC, you know, it's RISC-V compatible, so it's basically a derived ISA from RISC-V. When you actually build code, you build it to RISC-V, and then you just run a sort of a swift one-pass recompiler and it turns it from RISC-V into PVM.

PVM is essentially a preprocessing step that makes it a lot easier and more optimal to then recompile it further into x64. So, we're kind of using RISC-V and PVM as intermediate targets to make it, that are good for consensus code, good for gas metering, but not as bulky and potentially ambiguous as strict. And the great thing about having guest VMs is that you can, at least ones that you can read the memory of, sort of peek and poke into the memory, is that we can pack up the VM execution and then start it again in the next block in some, you know, stateless way, such that the guest of that virtual machine doesn't realize it has been stopped and restarted. This gives us the apparent continuous execution for these guests. So, you can think of core VM as essentially a sort of docker, a sort of container for regular software, regular sort of, a regular machine.

How does it work? Well, basically it sort of initializes, it registers to like zero, it's programmed counter to zero, empty page tables, memory is empty. It sets the code, it's a Harvard architecture machine, so the code sits outside of memory. And then it basically advances it, either just doing regular computation, if it doesn't need to read anything from memory. If it gets out of gas, it basically just snapshots all of its memory and sticks it in the data lake, a big data availability system that Jam provides.

If it's a page fault, it tries to fetch the data from the data lake, or introduces zero page in the table if there isn't already a page in that place in memory. And on a, there are host calls that allow it to output data basically to, in a sort of, I don't know, kind of output like graphics card, sound card, kind of like beyond the machine, some destination for data beyond the machine. And we provide this through a particular host call, almost like a sort of, an operating system sort of call. I'm not gonna go into the architecture particularly, it's, I don't have really time. So there's a bunch of tools, a tool for monitoring these output streams, so virtual hardware, a virtual monitor, virtual speakers, et cetera, et cetera, a virtual console.

Because of course, we want regular software to run in this. And a builder, which basically just works out, it's a memory manager basically, it works out which memory pages are needed for any given sort of execution slice of the machine. Right, let's see if I can make this work. I sort of, I thought everything was already set up from the last, what's it, the last presentation I gave, and then I sort of turned the laptop on just to make sure that it was all ready and waiting, and it turned out that I had installed a different distribution of Linux, and didn't really have a, well, didn't have any kind of setup on it. So I very quickly, 15 minutes before coming to this talk, tried to set everything up again, which took, I haven't had time to actually test it.

So it may or may not work, I mean, I don't even, oh, wow, it's actually, is that, no, I need to mirror it. How do I mirror it on here? Settings, settings, which of these is settings? Applications, settings, ah, here we go. Settings, displays, external display, mirror.

Mirror, does that work? Yes, all right, we're going. Right, now, so I'm gonna start a test net. No, I'm not, oh, dear. This doesn't usually break.

What is going on? Ah, yes, okay, now, I see. I just have to run this, this mad line here, and probably I need to sudo it. And then run the test net, okay. So the test net is sort of started, and it's doing a thing.

All this has done is spun up six nodes on my laptop, and then each node is running a, is a jam node, so they're all sort of talking to each other, and then I've got this program called Jam Top, which is a bit like Top, I don't know if you know Top. Like, it's a Unix utility. It shows you what's going on on your machine. In this case, there is only one thing going on on the Jam machine, which is the Bootstrap service. The Bootstrap service is basically like a BIOS or whatever, like firmware, that lets you load other software onto Jam and kick it off.

Now, the first thing I need to do is load some data onto Jam, which I'm gonna do this. This starts, oh dear, battery is low. It starts a, well, hopefully it's not that low. Okay, 19%, we might be okay. It starts a virtual file system on Jam, on the blockchain, and uploads some data to it.

It takes a little bit of data, so it's gonna spend a little bit of time uploading, and you can see the upload happening basically with this P flag here, I don't know if you can see that. No, you can't, it's really small. I'm not sure why it's so small. Maybe I can make it bigger. Bigger, how do I make it bigger?

14-inch laptop, it's like project to resolution. Yeah, I don't know. Anyone know how to use this like Cosmic thing? No, all right, never mind. Anyway, so that has been now uploaded.

You can just see that's been uploaded. So that's finished there. And what we're gonna do next is make a new VM. I'm gonna copy from my cheat sheet. Now, what this command does, you can't really see it, I'm sure, is it starts a new VM using this Jam tool, Jamty, which connects to the network, just to one of them.

It actually spins up its own node, the node connects to the network. It introduces a new process into Jam, and then that process is this core VM process, this kind of Docker, if you like. And then it immediately takes that process, once it's been created, that sort of executable, and tells it, I want you to start this other guest executable inside of your container. So it's a bit like saying Docker, I don't know, with a Linux thing, and then start, I don't know, Apache. It's a bit like doing that in DevOps terms.

Let's see if I can make this at least a bit bigger. Control plus, I'm on Mac usually, so this is. Made it bigger for me, oh, nice. Okay, cool. Can I make it brighter?

No, I don't know, I don't wanna jinx it. Maybe they can make it brighter. Maybe the gods of the projector can make it brighter. Okay, so that's completed, right? So what that's done is it's just basically, as I said, created this kind of VM container, and then initialized it with a program.

And we get given the service ID. This is like a process ID, right? So if you're on Linux or Unix, all the processes that are running will have an ID. It's like a number, and this, it gives you the same thing. You can see it down here.

You can see the same thing up here on Jamtop, right? It's the same thing. And if you, I don't know if you can see it, but it's like, it tells you on Jamtop, right? There's a VM. This service is a VM, and the thing running in it, well, that's this thing here.

So the next thing that we need to do is we need to connect the output of this Docker to an actual monitor, right? To something so we can see what's going on inside of the Docker container, basically. And that's what we're doing here. And in order for this guy to sort of know which VM it should be connecting the monitor into, we need to give it this ID, right? This process ID, this service ID.

So that's what I've just done there, and then what I'm doing here is I'm telling it to start actually ticking it along, yeah? Because someone's gonna have to sort of pay or whatever for this thing to run, so it's not free. Network is unreachable, right? This, I remember this problem from before, and this is because I don't have Wi-Fi. So let me put Wi-Fi on.

Do we have a, I just used my phone. Right, now, when you're doing personal hotspots, you need to go into the settings and like flick this personal hotspot thing, and eventually it should turn up, right? I mean, maybe, oh, there we go, okay. Connect, connect, how do I connect? There we go.

Is that gonna work? Thinking about it. Thinking about it. Still thinking. Okay, do we have a password for the protocol Berg network or any of these, really?

Department of Decentralization, okay. I don't know that one. Department of Decentralization, okay. Okay. Is that gonna work?

That might have worked. Looks, yeah. Let's see. No. Network is still unreachable.

Does that mean it's connected? No, right? Okay, so we have the monitor there. We have this, yeah, it's got this dot, dot, dot thing going on. Which I'm not confident means connected.

I'm gonna, okay. Right, I'm gonna turn it off and on again, and hopefully. All right, it's off. Airplane mode on, right? Airplane mode off.

Wi-Fi on. Department of Decentralization. Why is this white thing here? It's not doing anything. I've got a feeling that it's like breaking at the, uh-huh.

Try the protocol first, right? Protocol there. Okay. Come on. Hmm.

Yeah. Right, well, I'm afraid you're gonna be denied the call thing. But this is a, what it was gonna do is send a bunch of, or send work packages into the JAM network, which ticked forward this virtual machine. And that would have resulted in output going into the virtual monitor, which was going to be, which is monitored by our monitor program here, which would have made a window and displayed what was going on in the machine. And if you can read that there, which you can't really, it would have displayed the game Quake proceeding.

Good. Well, not really, but that's, it's like definitely not happy with the network. Good, great. That's about all I came to say, I think. If there is any time, I'm going to take a question.

Automatic transcript — names and jargon may be misspelled.