From 7ba5d5ef86d619ce81e81686057ac76874086e71 Mon Sep 17 00:00:00 2001 From: Anatoly Yakovenko Date: Thu, 21 Jun 2018 11:31:21 -0700 Subject: [PATCH] first! --- rfcs/images/smart-contracts-stack.png | Bin 0 -> 34728 bytes rfcs/rfc-001-smart-contracts-engine.md | 140 +++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 rfcs/images/smart-contracts-stack.png create mode 100644 rfcs/rfc-001-smart-contracts-engine.md diff --git a/rfcs/images/smart-contracts-stack.png b/rfcs/images/smart-contracts-stack.png new file mode 100644 index 0000000000000000000000000000000000000000..66ced3c0c384a66c516d934594ea30a69b3bc72d GIT binary patch literal 34728 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 literal 0 HcmV?d00001 diff --git a/rfcs/rfc-001-smart-contracts-engine.md b/rfcs/rfc-001-smart-contracts-engine.md new file mode 100644 index 0000000000..724c40d97b --- /dev/null +++ b/rfcs/rfc-001-smart-contracts-engine.md @@ -0,0 +1,140 @@ +# Smart Contracts Engine + +Our approach to smart contract execution is based on how operating systems load and execute dynamic code in the kernel.  + +![Figure 1. Smart Contracts Stack](images/smart-contracts-stack.png) + +In Figure 1. an untrusted client, or *Userspace* in Operating Systems terms, creates a program in the front-end language of her choice, (like C/C++/Rust/Lua), and compiles it with LLVM to the Solana Bytecode object. This object file is a standard ELF. We use the section headers in the ELF format to annotate memory in the object such that the Kernel aka the Solana blockchain, can safely and efficiently load it for execution. + +The computationally expensive work of converting frontend languages into programs is done locally by the client. The output is a ELF with specific section headers and with a bytecode as its target that is designed for quick verification and conversion to the local machine instruction set that Solana is running on. + +## Solana Bytecode + +Our bytecode is based on Berkley Packet Filter. The requirements for BPF overlap almost exactly with the requirements we have + +1. Deterministic amount of time to execute the code +2. Bytecode that is portable between machine instruction sets +3. Verified memory accesses +4. Fast to load the object, verify the bytecode and JIT to local machine instruction set + +For 1 BPF toolchain is designed for generating code without jumps back. For us this means loops are unrolled, and the stack itself is part of the ELF. Any work that we do here to expand how the kernel can analyze the runtime of the generated code can be ported back to the Linux community. + +For 2, the bytecode already easily maps to x86–64, arm64 and other instruction sets.  + +For 3 and 4, is in a single pass we want to check that all the load and stores are pointing to the memory defined in the ELF,and map all the instructions to x86 or SPIR-V, or some other local machine instruction set. Linux already ships with a BPF JIT, but we love Rust, so would likely reimplemnt it in rust. + +## Loader aka Dynamic Linker +The loader is our first smart contract. The job of this contract is to load the actual program with its own instance data. + +## Parallelizable Runtime +To parallelize smart contract execution we plan on breaking up contracts into distinct sections, Map/Collect/Reduce/Finalize. These distinct sections are the interface between the ELF and the Kernel that is executing it. Memory is loaded into the symbols defined in these sections, and relevant constants are set. +``` +struct Vote { + Address from; + uint64_t amount; + uint8_t favorite; +} +__section("map.data") +struct Vote vote; +__section("map") +void map(struct Transaction *tx) +{ + memmove(&vote.from, &tx.from, sizeof(vote.from)); + vote.amount = tx.amount; + vote.favorite = tx.userdata[0]; + yield(collect); +} +``` +The contract's object file implements a map function and lays out memory that is allocated per transaction. It then yields itself to a collect call that is schedule to run sometime later. +``` +__section("collect.map.len") +const uint32_t votelen; +__section("collect.map.data") +const struct Vote vote[votelen]; +__section("collect.data") +Vote totals[votelen]; +__section("collect.data.used") +uint32_t used; +__section("collect") +void collect() +{ + used = sizeof(struct Vote) * votelen; + memmove(totals, vote, used); + yield(reduce) +} +Then we simply reduce multiple collect objects into 1 data structure. Reduce additionally sees its own previous output from multiple calls to reduce. +__section("reduce.collect.len") +const uint32_t len; +__section("reduce.collect.data") +const struct Vote *vote[len]; +__section("reduce.collect.data.sizes") +const uint32_t sizes[len]; +//partially reduced contracts are also available to reduce +//so it can fold over it's own output +__section("reduce.reduce.len") +const uint32_t rlen; +__section("reduce.reduce.data") +Vote *rtotals[rlen]; +__section("reduce.reduce.data.sizes") +const uint32_t rsizes[rlen]; +//total memory available for reduce `data` +//this is the sum of all the reduce and collect allocations +__section("reduce.data.total") +const uint32_t total; +__section("reduce.data") +Vote totals[total/sizeof(struct Vote)]; +__section("reduce.data.used") +uint32_t used; +__section("reduce") +void reduce() +{ + int i; + for(i = 0; i < len; ++i) { + memmove(&totals[used/sizeof(struct Vote)], vote[i], sizes[i]); + used += sizes[i]; + } + for(i = 0; i < rlen; ++i) { + memmove(&totals[used/sizeof(struct Vote)], rtotals[i], rsizes[i]); + used += rsizes[i]; + } +} +``` +finalize is then called when some final condition occurs. This could be when the time expires on the contract, or from a direct call to finalize itself, such as yield(finalize).  +``` +__section("finalize.reduce.data.used") +const uint32_t used; +__section("finalize.reduce.data") +Vote totals[used/sizeof(struct Vote)]; +__section("finalize.data") +uint64_t votes[256]; +__section("finalize") +void finalize() { + int i; + uint64_t total = 0; + uint8_t max = 0; + uint32_t num = used/sizeof(struct Vote); + //scan all the votes and find out which uint8_t is the favorite + for(i = 0; i < num; ++i) { + struct Vote *v = &totals[i]; + votes[v->favorite] += v->amount; + if votes[max] < votes[v->favorite] { + max = v->favorite + } + total += v->amount; + } + for(i = 0; i < num; ++i) { + struct Vote *v = &totals[i]; + if v->favorite == max { + payout(v->from, total * v->amount / votes[max]); + } + } +} +``` +## Notes +1. There is no dynamic memory allocation.  +2. You need to derive the maximum amount of memory you need based on the number of user inputs flowing through the contract. +3. You need to tell the engine how much you are actually using so it saves that amount as persistent. +4. Loops need to be unrolled, and the contract will need to yield back to itself with the loop context saved. This means the stack for each function is something we load/store just like any other memory defined in the ELF +Other information about the kernel (current hash, contract address and balance, etc…) can be mapped into the elf as well. +5. We can map more complex data structured as well, like maps and hashtables, lists etc… +6. We can map instance configurable data as another section. So contracts can configure and create themselves.