Add blockchain smart contract lab
This commit is contained in:
parent
bedb845270
commit
945b2a09a7
|
|
@ -284,6 +284,7 @@ Run a read-only health snapshot from the Debian server with:
|
||||||
./jeannie resource-budget
|
./jeannie resource-budget
|
||||||
./jeannie artifact-cache status
|
./jeannie artifact-cache status
|
||||||
./jeannie blockchain-devnet status
|
./jeannie blockchain-devnet status
|
||||||
|
./jeannie blockchain-test
|
||||||
./jeannie golden-ledger check
|
./jeannie golden-ledger check
|
||||||
./jeannie route-inventory
|
./jeannie route-inventory
|
||||||
./jeannie workers list
|
./jeannie workers list
|
||||||
|
|
@ -374,6 +375,10 @@ cache. Use `artifact-cache instructions` for client configuration snippets.
|
||||||
`infra/blockchain-devnet`. It is for contract, wallet, RPC, and observability
|
`infra/blockchain-devnet`. It is for contract, wallet, RPC, and observability
|
||||||
learning only; never use real seed phrases or mainnet keys.
|
learning only; never use real seed phrases or mainnet keys.
|
||||||
|
|
||||||
|
`blockchain-test` runs the Foundry tests in `labs/blockchain`. The lab starts
|
||||||
|
with a simple `Counter` contract and ownership tests so there is a known-good
|
||||||
|
baseline before practicing vulnerable contracts.
|
||||||
|
|
||||||
`golden-ledger` shows or validates `infra/pimox/golden-image-ledger.yml`, the
|
`golden-ledger` shows or validates `infra/pimox/golden-image-ledger.yml`, the
|
||||||
reviewable record of template VMID, storage, OS release, Kubernetes pins,
|
reviewable record of template VMID, storage, OS release, Kubernetes pins,
|
||||||
runtime versions, and build metadata for Pimox worker golden images.
|
runtime versions, and build metadata for Pimox worker golden images.
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,7 @@ Run a read-only health snapshot from the Debian server with:
|
||||||
./{{ main_script }} resource-budget
|
./{{ main_script }} resource-budget
|
||||||
./{{ main_script }} artifact-cache status
|
./{{ main_script }} artifact-cache status
|
||||||
./{{ main_script }} blockchain-devnet status
|
./{{ main_script }} blockchain-devnet status
|
||||||
|
./{{ main_script }} blockchain-test
|
||||||
./{{ main_script }} golden-ledger check
|
./{{ main_script }} golden-ledger check
|
||||||
./{{ main_script }} route-inventory
|
./{{ main_script }} route-inventory
|
||||||
./{{ main_script }} workers list
|
./{{ main_script }} workers list
|
||||||
|
|
@ -374,6 +375,10 @@ cache. Use `artifact-cache instructions` for client configuration snippets.
|
||||||
`infra/blockchain-devnet`. It is for contract, wallet, RPC, and observability
|
`infra/blockchain-devnet`. It is for contract, wallet, RPC, and observability
|
||||||
learning only; never use real seed phrases or mainnet keys.
|
learning only; never use real seed phrases or mainnet keys.
|
||||||
|
|
||||||
|
`blockchain-test` runs the Foundry tests in `labs/blockchain`. The lab starts
|
||||||
|
with a simple `Counter` contract and ownership tests so there is a known-good
|
||||||
|
baseline before practicing vulnerable contracts.
|
||||||
|
|
||||||
`golden-ledger` shows or validates `infra/pimox/golden-image-ledger.yml`, the
|
`golden-ledger` shows or validates `infra/pimox/golden-image-ledger.yml`, the
|
||||||
reviewable record of template VMID, storage, OS release, Kubernetes pins,
|
reviewable record of template VMID, storage, OS release, Kubernetes pins,
|
||||||
runtime versions, and build metadata for Pimox worker golden images.
|
runtime versions, and build metadata for Pimox worker golden images.
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,10 @@ Docker Hub pull-through image caching.
|
||||||
`infra/blockchain-devnet`. This is for local learning only; never use real seed
|
`infra/blockchain-devnet`. This is for local learning only; never use real seed
|
||||||
phrases or mainnet keys.
|
phrases or mainnet keys.
|
||||||
|
|
||||||
|
`blockchain-test [forge args...]`
|
||||||
|
: Run the Foundry smart contract tests in `labs/blockchain`. Extra arguments are
|
||||||
|
passed through to `forge test`.
|
||||||
|
|
||||||
`golden-ledger {show|check}`
|
`golden-ledger {show|check}`
|
||||||
: Show or validate the Pimox golden image version ledger.
|
: Show or validate the Pimox golden image version ledger.
|
||||||
|
|
||||||
|
|
|
||||||
8
jeannie
8
jeannie
|
|
@ -6012,6 +6012,10 @@ blockchain_devnet() {
|
||||||
"${REPO_ROOT}/scripts/blockchain-devnet" "${@:2}"
|
"${REPO_ROOT}/scripts/blockchain-devnet" "${@:2}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blockchain_test() {
|
||||||
|
"${REPO_ROOT}/scripts/blockchain-test" "${@:2}"
|
||||||
|
}
|
||||||
|
|
||||||
golden_ledger() {
|
golden_ledger() {
|
||||||
"${REPO_ROOT}/scripts/golden-ledger" "${@:2}"
|
"${REPO_ROOT}/scripts/golden-ledger" "${@:2}"
|
||||||
}
|
}
|
||||||
|
|
@ -6080,6 +6084,7 @@ Build And Bootstrap
|
||||||
Manage optional Debian artifact caches.
|
Manage optional Debian artifact caches.
|
||||||
blockchain-devnet {status|up|down|logs|rpc}
|
blockchain-devnet {status|up|down|logs|rpc}
|
||||||
Manage the local Ethereum Anvil devnet.
|
Manage the local Ethereum Anvil devnet.
|
||||||
|
blockchain-test [forge args...] Run Foundry tests for labs/blockchain.
|
||||||
golden-ledger {show|check} Show or validate Pimox golden image versions.
|
golden-ledger {show|check} Show or validate Pimox golden image versions.
|
||||||
|
|
||||||
Cluster Lifecycle
|
Cluster Lifecycle
|
||||||
|
|
@ -6218,6 +6223,9 @@ case "${1:-}" in
|
||||||
blockchain-devnet)
|
blockchain-devnet)
|
||||||
blockchain_devnet "$@"
|
blockchain_devnet "$@"
|
||||||
;;
|
;;
|
||||||
|
blockchain-test)
|
||||||
|
blockchain_test "$@"
|
||||||
|
;;
|
||||||
golden-ledger)
|
golden-ledger)
|
||||||
golden_ledger "$@"
|
golden_ledger "$@"
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
# Blockchain Contract Lab
|
||||||
|
|
||||||
|
This is the local smart contract workspace for the homelab. It uses Foundry
|
||||||
|
because it is fast, test-oriented, and works well with a local Anvil devnet.
|
||||||
|
|
||||||
|
Never put real private keys, seed phrases, or funded wallet data in this repo.
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
```text
|
||||||
|
labs/blockchain/
|
||||||
|
foundry.toml
|
||||||
|
src/
|
||||||
|
test/
|
||||||
|
script/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./jeannie blockchain-test
|
||||||
|
```
|
||||||
|
|
||||||
|
The wrapper uses a local `forge` binary when available, otherwise it runs the
|
||||||
|
Foundry Docker image with this directory mounted.
|
||||||
|
|
||||||
|
## Deploy To The Local Devnet
|
||||||
|
|
||||||
|
Start the local devnet:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./jeannie blockchain-devnet up
|
||||||
|
```
|
||||||
|
|
||||||
|
Deploy using one of Anvil's generated dev private keys:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd labs/blockchain
|
||||||
|
PRIVATE_KEY=0x... forge script script/DeployCounter.s.sol \
|
||||||
|
--rpc-url http://127.0.0.1:8545 \
|
||||||
|
--broadcast
|
||||||
|
```
|
||||||
|
|
||||||
|
Use only Anvil dev keys. Do not paste a real wallet key into a shell.
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
[profile.default]
|
||||||
|
src = "src"
|
||||||
|
out = "out"
|
||||||
|
libs = ["lib"]
|
||||||
|
test = "test"
|
||||||
|
script = "script"
|
||||||
|
solc_version = "0.8.26"
|
||||||
|
optimizer = true
|
||||||
|
optimizer_runs = 200
|
||||||
|
fs_permissions = [
|
||||||
|
{ access = "read", path = "./" }
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.26;
|
||||||
|
|
||||||
|
import {Script} from "forge-std/Script.sol";
|
||||||
|
import {Counter} from "../src/Counter.sol";
|
||||||
|
|
||||||
|
contract DeployCounter is Script {
|
||||||
|
function run() external returns (Counter counter) {
|
||||||
|
uint256 deployerKey = vm.envUint("PRIVATE_KEY");
|
||||||
|
|
||||||
|
vm.startBroadcast(deployerKey);
|
||||||
|
counter = new Counter(0);
|
||||||
|
vm.stopBroadcast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.26;
|
||||||
|
|
||||||
|
contract Counter {
|
||||||
|
uint256 public number;
|
||||||
|
address public owner;
|
||||||
|
|
||||||
|
error NotOwner();
|
||||||
|
|
||||||
|
event NumberChanged(uint256 previousNumber, uint256 newNumber);
|
||||||
|
|
||||||
|
constructor(uint256 initialNumber) {
|
||||||
|
owner = msg.sender;
|
||||||
|
number = initialNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setNumber(uint256 newNumber) external {
|
||||||
|
if (msg.sender != owner) {
|
||||||
|
revert NotOwner();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 previousNumber = number;
|
||||||
|
number = newNumber;
|
||||||
|
emit NumberChanged(previousNumber, newNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
function increment() external {
|
||||||
|
uint256 previousNumber = number;
|
||||||
|
number++;
|
||||||
|
emit NumberChanged(previousNumber, number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.26;
|
||||||
|
|
||||||
|
import {Test} from "forge-std/Test.sol";
|
||||||
|
import {Counter} from "../src/Counter.sol";
|
||||||
|
|
||||||
|
contract CounterTest is Test {
|
||||||
|
Counter private counter;
|
||||||
|
address private owner = address(0xA11CE);
|
||||||
|
address private stranger = address(0xB0B);
|
||||||
|
|
||||||
|
function setUp() public {
|
||||||
|
vm.prank(owner);
|
||||||
|
counter = new Counter(41);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testInitialNumberAndOwner() public view {
|
||||||
|
assertEq(counter.number(), 41);
|
||||||
|
assertEq(counter.owner(), owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testOwnerCanSetNumber() public {
|
||||||
|
vm.prank(owner);
|
||||||
|
counter.setNumber(100);
|
||||||
|
|
||||||
|
assertEq(counter.number(), 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testNonOwnerCannotSetNumber() public {
|
||||||
|
vm.prank(stranger);
|
||||||
|
vm.expectRevert(Counter.NotOwner.selector);
|
||||||
|
counter.setNumber(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testAnyoneCanIncrement() public {
|
||||||
|
vm.prank(stranger);
|
||||||
|
counter.increment();
|
||||||
|
|
||||||
|
assertEq(counter.number(), 42);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
LAB_DIR="${REPO_ROOT}/labs/blockchain"
|
||||||
|
FOUNDRY_IMAGE="${FOUNDRY_IMAGE:-ghcr.io/foundry-rs/foundry:latest}"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: ./jeannie blockchain-test [forge args...]
|
||||||
|
|
||||||
|
Run Foundry tests for labs/blockchain. Extra arguments are passed to forge test.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
-h|--help|help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if command -v forge >/dev/null 2>&1; then
|
||||||
|
cd "$LAB_DIR"
|
||||||
|
exec forge test "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v docker >/dev/null 2>&1; then
|
||||||
|
echo "forge or docker is required for blockchain-test." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec docker run --rm \
|
||||||
|
-v "${LAB_DIR}:/workspace" \
|
||||||
|
-w /workspace \
|
||||||
|
"$FOUNDRY_IMAGE" \
|
||||||
|
forge test "$@"
|
||||||
Loading…
Reference in New Issue