Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Programmability - prep for merge #213

Merged
merged 51 commits into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
6c778a9
Implement ticket machine component
metalicjames Sep 16, 2022
416d230
Implement runtime locking shard component
metalicjames Sep 22, 2022
86ab671
Implement directory library
metalicjames Sep 22, 2022
eaa3aca
Implement broker library
metalicjames Sep 22, 2022
c7a9d08
Implement agent library and specify runner interface
metalicjames Sep 22, 2022
a91ccea
Implement Lua execution environment and agentd component
metalicjames Sep 26, 2022
46375f8
Implement EVM agent runner
metalicjames Oct 21, 2022
c6499c4
Add EVM runner to agent daemon
metalicjames Oct 25, 2022
2ca85bb
Implement EVM load generator
metalicjames Oct 25, 2022
100925c
Add 3PC docker compose configurations
metalicjames Oct 26, 2022
f841c8a
Increase integration and unit test timeout in github actions
metalicjames Oct 26, 2022
02fb2c0
Complete Geth-compatible RPC implementation
wadagso-gertjaap Oct 28, 2022
e3dc583
Add runner tests to unit tests binary
metalicjames Dec 20, 2022
226ab39
Fix crash bug where hex parsing algorithm didn't check array bounds
metalicjames Jan 6, 2023
c080e27
Fix bug where gas refund did not account for gas price
metalicjames Jan 6, 2023
66b711a
Fix bug where block timestamp was not a UNIX timestamp
metalicjames Jan 6, 2023
8a65424
Return transaction receipt status
metalicjames Jan 9, 2023
6a59d36
Changes to compile in macos arm64
AlexRamRam Dec 21, 2022
9086a59
use override keyword
AlexRamRam Jan 20, 2023
c12e040
Remove postinstall step, do not copy hpp file to parent in build step
AlexRamRam Feb 7, 2023
f37bbf2
broker::interface::begin_return_type --> ticketnum_or_errcode_type
AlexRamRam Mar 3, 2023
a2e96b5
evm_runner: convert some member functions to static with explicit par…
AlexRamRam Mar 3, 2023
f981105
use if/else blocks in agent::impl::do_start()
AlexRamRam Mar 3, 2023
5774d01
rename agent::impl::handle_try_lock_request() --> do_try_lock_request()
AlexRamRam Mar 4, 2023
3bcd084
cast to unsigned long to make clang++ happy
AlexRamRam Mar 9, 2023
53f2e95
Change symbols named "dry_run" to "is_readonly_run"
AlexRamRam Mar 15, 2023
65d545f
remove accessor function evm_host::get_tx_receipt()
AlexRamRam Mar 15, 2023
d6c6298
Hanging `dry_run` instance, update for Doxygen
maurermi Apr 5, 2023
c813e94
Linting fixes
maurermi Apr 6, 2023
95f71c1
In http_server::exec_tx() fix error propagation via json value object
AlexRamRam Apr 8, 2023
3ff538e
JSON RPC method eth_estimateGas is not supported - move to handle_sta…
AlexRamRam Apr 8, 2023
bb34ee0
Remove parse_bytes32 (obsolete method)
maurermi Apr 10, 2023
8565499
Return errors to user in http_server
maurermi Apr 10, 2023
89bbed2
Address remaining review comments
maurermi Apr 10, 2023
546b09f
Update evm JSON error codes to align with standard
maurermi Apr 19, 2023
ec9e08d
Add member function lock_tx_receipt to agent/runner/evm
maurermi Apr 24, 2023
dc670a0
Add end-to-end integration test for 3PC EVM runner
AlexRamRam Apr 14, 2023
c841c9c
Rename header guard prefix
AlexRamRam May 1, 2023
4e441bc
Confirm EVM instance is ABI compatible with the current EVMC API
AlexRamRam May 3, 2023
daaf5a5
Add more erc20 tests to 3pc integration test, fix sample C++ ABI inte…
AlexRamRam May 2, 2023
775ff9c
Documentation for Programmability Architecture
AlexRamRam May 4, 2023
bebfdc8
Set transaction receipt status to 1 for native value transfers
AlexRamRam May 11, 2023
314f18e
Adds 3pc demo tools, and a script to run locally
maurermi May 16, 2023
9749669
Adds programmability user guide
maurermi May 12, 2023
42b59d2
Gracefully return error when write-locks requested for read-only tran…
AlexRamRam May 22, 2023
001914e
Address several style/documentation/aesthetic issues
AlexRamRam Jun 5, 2023
6b8c33c
Generate lua_bench bytecode at runtime
maurermi Jun 5, 2023
287d00b
Add doc comments for public methods
maurermi Jun 8, 2023
1605c22
Fix in contract deployment
AlexRamRam Jul 21, 2023
eefcdf2
Rename 3PC -> PArSEC
maurermi Jun 21, 2023
c9a301c
fix: reconcile docs for rename and updates
HalosGhost Jul 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
# TODO: Renable bugprone-easily-swappable-parameters
Checks: '
clang-analyzer-*,
bugprone-*,
-bugprone-easily-swappable-parameters,
modernize-*,
performance-*,
portability-*,
cppcoreguidelines-*,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
readability-*,
google-explicit-constructor,
-readability-identifier-length'
clang-analyzer-*,
bugprone-*,
-bugprone-easily-swappable-parameters,
modernize-*,
performance-*,
portability-*,
cppcoreguidelines-*,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
readability-*,
google-explicit-constructor,
-readability-identifier-length'
CheckOptions:
- {key: cppcoreguidelines-explicit-virtual-functions.AllowOverrideAndFinal, value: true}
- {key: modernize-use-override.AllowOverrideAndFinal, value: true}
WarningsAsErrors: '*'
FormatStyle: 'file'
HeaderFilterRegex: 'hpp'
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ scripts/
!scripts/test.sh
!scripts/configure.sh
!scripts/test-transaction.sh
!scripts/wait-for-it.sh

# Improves caching significantly
.git
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
unit-and-integration-test:
name: Unit and Integration Tests
runs-on: ubuntu-20.04
timeout-minutes: 15
timeout-minutes: 30
steps:
- uses: actions/checkout@v2
with:
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ CMakeCache.txt

leveldb*/
NuRaft*/
curl*/
jsoncpp*/
ethash*/
lua*/
benchmark-results/
CMakeFiles/
plots/
Expand Down
2 changes: 2 additions & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
v18.16.0

14 changes: 13 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.10)
cmake_minimum_required(VERSION 3.13)
include(CheckCXXCompilerFlag)

project(opencbdc-tx)
Expand All @@ -7,6 +7,8 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_EXTENSIONS False)

cmake_policy(SET CMP0076 NEW)

try_compile(USE_STDFS_LIB ${CMAKE_BINARY_DIR} "${CMAKE_SOURCE_DIR}/cmake-tests/test-libstdc++fs.cpp" LINK_LIBRARIES "stdc++fs")
check_cxx_compiler_flag(-Wshadow-all W_SHADOW_ALL)
check_cxx_compiler_flag(-Wnewline-eof W_NEWLINE_EOF)
Expand All @@ -33,6 +35,16 @@ find_library(NURAFT_LIBRARY nuraft REQUIRED)
find_library(GTEST_LIBRARY gtest REQUIRED)
find_library(GTEST_MAIN_LIBRARY gtest_main REQUIRED)
find_package(benchmark REQUIRED)
find_library(LUA_LIBRARY lua REQUIRED)
find_library(KECCAK_LIBRARY keccak REQUIRED)
find_library(EVMC_HEX_LIBRARY hex REQUIRED)
find_library(EVMC_INSTRUCTIONS_LIBRARY evmc-instructions REQUIRED)
find_library(EVMONE_LIBRARY evmone REQUIRED)
find_library(JSON_LIBRARY libjsoncpp.a jsoncpp REQUIRED)
find_library(CURL_LIBRARY libcurl.a curl REQUIRED)
find_library(MHD_LIBRARY libmicrohttpd.a REQUIRED)

set(LUA_LIBRARY "${LUA_LIBRARY}" "-ldl")

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")

Expand Down
18 changes: 18 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,21 @@ COPY --from=builder /opt/tx-processor/build/src/uhs/client/client-cli ./build/sr

# Copy atomizer config
COPY --from=builder /opt/tx-processor/atomizer-compose.cfg ./atomizer-compose.cfg

# Create PArSEC Deployment Image
FROM $IMAGE_VERSION AS parsec

# Set working directory
WORKDIR /opt/tx-processor

# Only copy essential binaries
COPY --from=builder /opt/tx-processor/build/src/parsec/agent/agentd ./build/src/parsec/agent/agentd
COPY --from=builder /opt/tx-processor/build/src/parsec/runtime_locking_shard/runtime_locking_shardd ./build/src/parsec/runtime_locking_shard/runtime_locking_shardd
COPY --from=builder /opt/tx-processor/build/src/parsec/ticket_machine/ticket_machined ./build/src/parsec/ticket_machine/ticket_machined

# Copy load generators
COPY --from=builder /opt/tx-processor/build/tools/bench/parsec/evm/evm_bench ./build/tools/bench/parsec/evm/evm_bench
COPY --from=builder /opt/tx-processor/build/tools/bench/parsec/lua/lua_bench ./build/tools/bench/parsec/lua/lua_bench

# Copy wait script
COPY --from=builder /opt/tx-processor/scripts/wait-for-it.sh ./scripts/wait-for-it.sh
177 changes: 27 additions & 150 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ The design decisions we made to achieve these goals will help inform policy make
**NOTE:** In cases where there are significant changes to the repository that might need manual intervention down-stream (or other important updates), we will [make a NEWS post](NEWS.md).

# Architecture

We explored two system architectures for transaction settlement, both based on an [unspent transaction output (UTXO)](https://en.wikipedia.org/wiki/Unspent_transaction_output) data model and transaction format.
We have explored several architectures under two broad categories as follows:
## UHS-Based Transaction Processor
We explored two system architectures for transaction settlement based on an [unspent transaction output (UTXO)](https://en.wikipedia.org/wiki/Unspent_transaction_output) data model and transaction format.
Both architectures implement the same schema representing an [unspent hash set (UHS)](https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-May/015967.html) abstraction.
One architecture provides [linearizability](https://en.wikipedia.org/wiki/linearizability) of transactions, whereas the other only provides [serializability](https://en.wikipedia.org/wiki/Serializability).
By relaxing the ordering constraint, the peak transaction throughput supported by the system scales horizontally with the number of nodes, but the transaction history is unavailable making the system harder to audit retroactively.
Both architectures handle multiple geo-distributed datacenter outages with a [recovery time objective (RTO)](https://en.wikipedia.org/wiki/Disaster_recovery#Recovery_Time_Objective) of under ten seconds and a [recovery point objective (RPO)](https://en.wikipedia.org/wiki/Disaster_recovery#Recovery_Point_Objective) of zero.

There are two UHS-based architectures as follows:
1. "Atomizer" architecture
- Materializes a total ordering of all transactions settled by the system in a linear sequence of batches.
- Requires vertical scaling as peak transaction throughput is limited by the performance of a single system component.
Expand All @@ -36,8 +38,22 @@ Both architectures handle multiple geo-distributed datacenter outages with a [re
- Maximum demonstrated throughput ~1.7M transactions per second.
- Geo-replicated latency <1 second.

Read the [architecture guide](docs/architecture.md) for a detailed description of the system components and implementation of each architecture.
Read the [2PC & Atomizer architecture guide](docs/uhs-architectures.md) for a detailed description of the system components and implementation of each architecture.

## Parallel Architecture for Scalably Executing smart Contracts ("PArSEC")
We built a system with a generic virtual machine layer that is capable of performing parallel executions of smart contracts.

The architecture is composed of two layers:
1. A distributed key-value data store with [ACID](https://en.wikipedia.org/wiki/ACID) database properties
- This back-end data store is not constrained to any type of data and is agnostic to the execution later.
1. A generic virtual machine layer that executes programs (i.e. smart contracts) and uses the distributed key-value data store to record state
- This computation layer defines the data models and transaction semantics.
- We have implemented the Ethereum Virtual Machine EVM and a Lua based virtual machine as two working examples.

- This architecture enables parallel execution of smart contracts which can be scaled horizontally where keys are independent.
- Unmodified smart contracts from the Ethereum ecosystem can be deployed directly onto our EVM implementation.

Read the [PArSEC Architecture Guide](docs/parsec_architecture.md) for more details.
# Contributing

You can [sign up](https://dci.mit.edu/opencbdc-interest) to receive updates from technical working groups and to learn more about our work.
Expand Down Expand Up @@ -73,152 +89,13 @@ Note that if you have not already installed the xcode cli tools you will need to
```terminal
# xcode-select --install
```

# Run the Code

The easiest way to compile the code and run the system locally is using [Docker](https://www.docker.com).

## Setup Docker

* [Install Docker](https://docs.docker.com/get-docker/)
* [Install docker-compose](https://docs.docker.com/compose/install/)

Don't forget to run the docker daemon!

## Build the containers

Building with Docker utilizes multi-stage builds. In order to run an architecture you will need to build each architecture independently if building locally.

**Note:** We have pre-built images available [here](#launch-the-system-with-a-pre-built-image) if you would rather pull the images from GitHub packages over building them locally.

1. Build 2PC architecture:
```terminal
$ cd opencbdc-tx # change to the project directory
$ sudo -s # open a root shell (needed for docker)
$ docker build --target twophase -t opencbdc-tx-twophase . # build the container
```
1. Build atomizer architecture:
```terminal
$ cd opencbdc-tx # change to the project directory
$ sudo -s # open a root shell (needed for docker)
$ docker build --target atomizer -t opencbdc-tx-atomizer . # build the container
```

## Launch the System

**Note:** You will need to both run the system and interact with it; you can either use two shells, or you can add the `--detach` flag when launching the system (note that it will then remain running till you stop it, e.g., with `docker stop`).

_The commands below will build a new image every time that you run it.
You can remove the `--build` flag after the image has been built to avoid rebuilding.
To run the system with our pre-built image proceed to the [next section](#launch-the-system-with-a-pre-built-image) for the commands to run._

1. Run the System
1. 2PC architecture:
```terminal
$ docker compose --file docker-compose-2pc.yml up --build
```
1. Atomizer architecture:
```terminal
$ docker compose --file docker-compose-atomizer.yml up --build
```
1. Launch a container in which to run wallet commands
1. 2PC architecture:
```terminal
$ docker run --network 2pc-network -ti opencbdc-tx-twophase /bin/bash
```
1. Atomizer architecture:
```terminal
$ docker run --network atomizer-network -ti opencbdc-tx-atomizer /bin/bash
```

## Launch the System With a Pre-built Image

We publish new docker images for all commits to `trunk`.
You can find the images [in the Github Container Registry](https://github.com/mit-dci/opencbdc-tx/pkgs/container/opencbdc-tx).

**Note:** You must use `docker compose` (not `docker-compose`) for this approach to work or you will need to pull the image manually `docker pull ghcr.io/mit-dci/opencbdc-tx-twophase` or `docker pull ghcr.io/mit-dci/opencbdc-tx-atomizer`.

1. Run the system
1. 2PC architecture:
```terminal
$ docker compose --file docker-compose-2pc.yml --file docker-compose-prebuilt-2pc.yml up --no-build
```
1. Atomizer architecture:
```terminal
$ docker compose --file docker-compose-atomizer.yml --file docker-compose-prebuilt-atomizer.yml up --no-build
```
1. Launch a container in which to run wallet commands
1. 2PC architecture:
```terminal
$ docker run --network 2pc-network -ti ghcr.io/mit-dci/opencbdc-tx-twophase /bin/bash
```
1. Atomizer architecture:
```terminal
$ docker run --network atomizer-network -ti ghcr.io/mit-dci/opencbdc-tx-atomizer /bin/bash
```

## Setup test wallets and test them

The following commands are all performed from within the second container we started in the previous step.
In each of the below commands, you should pass `atomizer-compose.cfg` instead of `2pc-compose.cfg` if you started the atomizer architecture.

* Mint new coins (e.g., 10 new UTXOs each with a value of 5 atomic units of currency)
```terminal
# ./build/src/uhs/client/client-cli 2pc-compose.cfg mempool0.dat wallet0.dat mint 10 5
[2021-08-17 15:11:57.686] [WARN ] Existing wallet file not found
[2021-08-17 15:11:57.686] [WARN ] Existing mempool not found
4bc23da407c3a8110145c5b6c38199c8ec3b0e35ea66bbfd78f0ed65304ce6fa
```

If using the atomizer architecture, you'll need to sync the wallet after:
```terminal
# ./build/src/uhs/client/client-cli atomizer-compose.cfg mempool0.dat wallet0.dat sync
```

* Inspect the balance of a wallet
```terminal
# ./build/src/uhs/client/client-cli 2pc-compose.cfg mempool0.dat wallet0.dat info
Balance: $0.50, UTXOs: 10, pending TXs: 0
```

* Make a new wallet
```terminal
# ./build/src/uhs/client/client-cli 2pc-compose.cfg mempool1.dat wallet1.dat newaddress
[2021-08-17 15:13:16.148] [WARN ] Existing wallet file not found
[2021-08-17 15:13:16.148] [WARN ] Existing mempool not found
usd1qrw038lx5n4wxx3yvuwdndpr7gnm347d6pn37uywgudzq90w7fsuk52kd5u
```

* Send currency from the first wallet to the second wallet created in the previous step (e.g., 30 atomic units of currency)
```terminal
# ./build/src/uhs/client/client-cli 2pc-compose.cfg mempool0.dat wallet0.dat send 30 usd1qrw038lx5n4wxx3yvuwdndpr7gnm347d6pn37uywgudzq90w7fsuk52kd5u
tx_id:
cc1f7dc708be5b07e23e125cf0674002ff8546a9342928114bc97031d8b96e75
Data for recipient importinput:
cc1f7dc708be5b07e23e125cf0674002ff8546a9342928114bc97031d8b96e750000000000000000d0e4f689b550f623e9370edae235de50417860be0f2f8e924eca9f402fcefeaa1e00000000000000
Sentinel responded: Confirmed
```

If using the atomizer architecture, you'll need to sync the sending wallet after:
```terminal
# ./build/src/uhs/client/client-cli atomizer-compose.cfg mempool0.dat wallet0.dat sync
```

* Check that the currency is no longer available in the sending wallet
```terminal
# ./build/src/uhs/client/client-cli 2pc-compose.cfg mempool0.dat wallet0.dat info
Balance: $0.20, UTXOs: 4, pending TXs: 0
```

* Import coins to the receiving wallet using the string after `importinput` from the currency transfer step above
```terminal
# ./build/src/uhs/client/client-cli 2pc-compose.cfg mempool1.dat wallet1.dat importinput cc1f7dc708be5b07e23e125cf0674002ff8546a9342928114bc97031d8b96e750000000000000000d0e4f689b550f623e9370edae235de50417860be0f2f8e924eca9f402fcefeaa1e00000000000000
# ./build/src/uhs/client/client-cli 2pc-compose.cfg mempool1.dat wallet1.dat sync
# ./build/src/uhs/client/client-cli 2pc-compose.cfg mempool1.dat wallet1.dat info
Balance: $0.30, UTXOs: 1, pending TXs: 0
```

## Testing
## UHS-based Architectures (2PC & Atomizer)
See the [2PC & Atomizer User Guide](docs/2pc_atomizer_user_guide.md)
## PArSEC Architecture
See the [PArSEC User Guide](docs/parsec_user_guide.md)
# Testing

Running Unit & Integration Tests

Expand All @@ -231,15 +108,15 @@ Running Unit & Integration Tests
$ docker run -ti opencbdc-tx-builder ./scripts/test.sh
```

### E2E Testing with Kubernetes
## E2E Testing with Kubernetes

#### Requirements
### Requirements
- Go (go test library used to run tests)
- Minikube
- Helm
- Kubectl

#### Running tests
### Running tests

1. `./scripts/build-docker.sh`
1. `./scripts/test-e2e-minikube.sh`
Expand Down
24 changes: 16 additions & 8 deletions benchmarks/transactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,14 @@ static void Nto1_tx(benchmark::State& state) {
GTEST_LOG_(ERROR) << state.range(0) << "-2 transaction invalid";
return;
}
ASSERT_EQ(wallet_a.balance(), SWEEP_MAX * 2 - 2 * state.range(0));
ASSERT_EQ(wallet_a.count(), SWEEP_MAX - state.range(0));
ASSERT_EQ(wallet_b.balance(), state.range(0) * 2);
ASSERT_EQ(wallet_b.count(), 1);
ASSERT_EQ(
wallet_a.balance(),
static_cast<unsigned long>(SWEEP_MAX * 2 - 2 * state.range(0)));
AlexRamRam marked this conversation as resolved.
Show resolved Hide resolved
ASSERT_EQ(wallet_a.count(),
static_cast<unsigned long>(SWEEP_MAX - state.range(0)));
ASSERT_EQ(wallet_b.balance(),
static_cast<unsigned long>(state.range(0) * 2));
ASSERT_EQ(wallet_b.count(), 1UL);
}
state.SetComplexityN(state.range(0));
}
Expand All @@ -117,10 +121,14 @@ static void Nto2_tx(benchmark::State& state) {
GTEST_LOG_(ERROR) << state.range(0) << "-2 transaction invalid";
return;
}
ASSERT_EQ(wallet_a.balance(), SWEEP_MAX * 2 - 2 * state.range(0) + 1);
ASSERT_EQ(wallet_a.count(), SWEEP_MAX - state.range(0) + 1);
ASSERT_EQ(wallet_b.balance(), state.range(0) * 2 - 1);
ASSERT_EQ(wallet_b.count(), 1);
ASSERT_EQ(wallet_a.balance(),
static_cast<unsigned long>(SWEEP_MAX * 2 - 2 * state.range(0)
+ 1));
ASSERT_EQ(wallet_a.count(),
static_cast<unsigned long>(SWEEP_MAX - state.range(0) + 1));
ASSERT_EQ(wallet_b.balance(),
static_cast<unsigned long>(state.range(0) * 2 - 1));
ASSERT_EQ(wallet_b.count(), 1UL);
}
state.SetComplexityN(state.range(0));
}
Expand Down
16 changes: 16 additions & 0 deletions contracts/MITCoin.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MITCoin is ERC20 {
constructor() ERC20("MITCoin", "MIT") {}

function mint(address to, uint256 amount) public {
_mint(to, amount);
}

function requestTokens(address to) public {
mint(to, 1 * 10**18);
}
}
Loading