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 artifact-cache status
|
||||
./jeannie blockchain-devnet status
|
||||
./jeannie blockchain-test
|
||||
./jeannie golden-ledger check
|
||||
./jeannie route-inventory
|
||||
./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
|
||||
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
|
||||
reviewable record of template VMID, storage, OS release, Kubernetes pins,
|
||||
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 }} artifact-cache status
|
||||
./{{ main_script }} blockchain-devnet status
|
||||
./{{ main_script }} blockchain-test
|
||||
./{{ main_script }} golden-ledger check
|
||||
./{{ main_script }} route-inventory
|
||||
./{{ 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
|
||||
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
|
||||
reviewable record of template VMID, storage, OS release, Kubernetes pins,
|
||||
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
|
||||
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}`
|
||||
: 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}"
|
||||
}
|
||||
|
||||
blockchain_test() {
|
||||
"${REPO_ROOT}/scripts/blockchain-test" "${@:2}"
|
||||
}
|
||||
|
||||
golden_ledger() {
|
||||
"${REPO_ROOT}/scripts/golden-ledger" "${@:2}"
|
||||
}
|
||||
|
|
@ -6080,6 +6084,7 @@ Build And Bootstrap
|
|||
Manage optional Debian artifact caches.
|
||||
blockchain-devnet {status|up|down|logs|rpc}
|
||||
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.
|
||||
|
||||
Cluster Lifecycle
|
||||
|
|
@ -6218,6 +6223,9 @@ case "${1:-}" in
|
|||
blockchain-devnet)
|
||||
blockchain_devnet "$@"
|
||||
;;
|
||||
blockchain-test)
|
||||
blockchain_test "$@"
|
||||
;;
|
||||
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