semfnode 1.0.0__tar.gz → 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {semfnode-1.0.0 → semfnode-1.1.0}/PKG-INFO +1 -2
- {semfnode-1.0.0 → semfnode-1.1.0}/pyproject.toml +1 -2
- semfnode-1.1.0/src/bc/__init__.py +723 -0
- {semfnode-1.0.0 → semfnode-1.1.0}/src/semfnode.egg-info/PKG-INFO +1 -2
- {semfnode-1.0.0 → semfnode-1.1.0}/src/semfnode.egg-info/SOURCES.txt +1 -0
- {semfnode-1.0.0 → semfnode-1.1.0}/src/semfnode.egg-info/top_level.txt +1 -0
- {semfnode-1.0.0 → semfnode-1.1.0}/setup.cfg +0 -0
- {semfnode-1.0.0 → semfnode-1.1.0}/src/dnn/__init__.py +0 -0
- {semfnode-1.0.0 → semfnode-1.1.0}/src/opti/__init__.py +0 -0
- {semfnode-1.0.0 → semfnode-1.1.0}/src/semfnode.egg-info/dependency_links.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: semfnode
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Kelp harvest scheduling utilities for coastal tide pools
|
|
5
5
|
Author: M. Holloway
|
|
6
6
|
License-Expression: MIT
|
|
@@ -16,4 +16,3 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
17
|
Classifier: Topic :: Scientific/Engineering :: Oceanography
|
|
18
18
|
Requires-Python: >=3.8
|
|
19
|
-
Description-Content-Type: text/markdown
|
|
@@ -4,9 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "semfnode"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.1.0"
|
|
8
8
|
description = "Kelp harvest scheduling utilities for coastal tide pools"
|
|
9
|
-
readme = "README.md"
|
|
10
9
|
license = "MIT"
|
|
11
10
|
requires-python = ">=3.8"
|
|
12
11
|
authors = [
|
|
@@ -0,0 +1,723 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Blockchain Practicals — lab code bank.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
import bc
|
|
6
|
+
bc.prac1() # prints Practical 1 code
|
|
7
|
+
bc.prac10() # prints Practical 10 code
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
__version__ = "1.0.0"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _show(code: str) -> str:
|
|
14
|
+
print(code)
|
|
15
|
+
return code
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def prac1():
|
|
19
|
+
return _show('''# Practical No. 1
|
|
20
|
+
# Aim: Installation of Ethereum, Truffle, Ganache, and other tools
|
|
21
|
+
|
|
22
|
+
# ------------------------------------------------------------
|
|
23
|
+
# SETUP / INSTALLATION STEPS
|
|
24
|
+
# ------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
# Step 1: Install Node.js and npm (required to run Truffle)
|
|
27
|
+
# Download the LTS installer from: https://nodejs.org/en/download
|
|
28
|
+
# Windows/Mac: run the installer and follow the prompts.
|
|
29
|
+
# Linux (Debian/Ubuntu):
|
|
30
|
+
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
|
|
31
|
+
sudo apt-get install -y nodejs
|
|
32
|
+
# Verify installation:
|
|
33
|
+
node -v
|
|
34
|
+
npm -v
|
|
35
|
+
|
|
36
|
+
# Step 2: Install Truffle globally via npm
|
|
37
|
+
npm install -g truffle
|
|
38
|
+
# Verify installation:
|
|
39
|
+
truffle version
|
|
40
|
+
|
|
41
|
+
# Step 3: Install Ganache (local Ethereum blockchain for testing)
|
|
42
|
+
# Option A - GUI app (recommended for beginners):
|
|
43
|
+
# Download from: https://trufflesuite.com/ganache/
|
|
44
|
+
# Option B - CLI version via npm:
|
|
45
|
+
npm install -g ganache
|
|
46
|
+
# Verify installation:
|
|
47
|
+
ganache --version
|
|
48
|
+
|
|
49
|
+
# Step 4: Install MetaMask (browser wallet to interact with contracts)
|
|
50
|
+
# Install the browser extension from: https://metamask.io/download/
|
|
51
|
+
# Available for Chrome, Firefox, Brave, and Edge.
|
|
52
|
+
|
|
53
|
+
# Step 5: Use Remix IDE (no installation needed)
|
|
54
|
+
# Open in any browser: https://remix.ethereum.org
|
|
55
|
+
# Used to write, compile, and deploy Solidity smart contracts directly.
|
|
56
|
+
|
|
57
|
+
# Step 6 (optional): VS Code + Solidity extension for local editing
|
|
58
|
+
# Download VS Code: https://code.visualstudio.com/
|
|
59
|
+
# Install the "Solidity" extension (by Juan Blanco) from the Extensions marketplace.
|
|
60
|
+
|
|
61
|
+
# ------------------------------------------------------------
|
|
62
|
+
# THEORY
|
|
63
|
+
# ------------------------------------------------------------
|
|
64
|
+
# Ethereum development requires a set of core tools:
|
|
65
|
+
# - Node.js & npm: JavaScript runtime and package manager needed to run Truffle
|
|
66
|
+
# - Truffle: a development framework for compiling, testing, and deploying smart contracts
|
|
67
|
+
# - Ganache: a personal Ethereum blockchain for local testing, with test accounts pre-funded
|
|
68
|
+
# with fake ETH
|
|
69
|
+
# - MetaMask/Remix: browser tools to interact with contracts and wallets
|
|
70
|
+
# Once installed, these tools together provide a complete local blockchain
|
|
71
|
+
# development environment.
|
|
72
|
+
|
|
73
|
+
# ------------------------------------------------------------
|
|
74
|
+
# OUTPUT
|
|
75
|
+
# ------------------------------------------------------------
|
|
76
|
+
# node -v / npm -v -> prints installed versions
|
|
77
|
+
# truffle version -> prints Truffle, Solidity, Node, Web3.js versions
|
|
78
|
+
# ganache --version -> prints Ganache CLI version
|
|
79
|
+
# Ganache running -> lists 10 test accounts, each pre-loaded with 100 ETH
|
|
80
|
+
''')
|
|
81
|
+
|
|
82
|
+
def prac2():
|
|
83
|
+
return _show('''# Practical No. 2
|
|
84
|
+
# Aim: Writing and Deploying Basic Smart Contracts on Ethereum
|
|
85
|
+
|
|
86
|
+
# ------------------------------------------------------------
|
|
87
|
+
# SETUP STEPS (uses Remix IDE - no local installation required)
|
|
88
|
+
# ------------------------------------------------------------
|
|
89
|
+
# Step 1: Open https://remix.ethereum.org in your browser
|
|
90
|
+
# Step 2: In the File Explorer, create a new file named "AddTwoNumbers.sol"
|
|
91
|
+
# Step 3: Paste the Solidity code below into the file
|
|
92
|
+
# Step 4: Go to the "Solidity Compiler" tab (left sidebar) and click "Compile AddTwoNumbers.sol"
|
|
93
|
+
# Step 5: Go to the "Deploy & Run Transactions" tab
|
|
94
|
+
# - Set ENVIRONMENT to "Remix VM (London)" (an in-browser test blockchain)
|
|
95
|
+
# - Click "Deploy"
|
|
96
|
+
# Step 6: Under "Deployed Contracts", expand the contract and call add(5, 3)
|
|
97
|
+
|
|
98
|
+
# ------------------------------------------------------------
|
|
99
|
+
# THEORY
|
|
100
|
+
# ------------------------------------------------------------
|
|
101
|
+
# Smart contracts are self-executing programs stored on the blockchain that
|
|
102
|
+
# automatically enforce the terms of an agreement.
|
|
103
|
+
# Key features:
|
|
104
|
+
# - Run on the Ethereum Virtual Machine (EVM)
|
|
105
|
+
# - Immutable once deployed
|
|
106
|
+
# - Transparent and verifiable by anyone on the network
|
|
107
|
+
# - Execute automatically without intermediaries
|
|
108
|
+
|
|
109
|
+
# ------------------------------------------------------------
|
|
110
|
+
# CODE (Solidity)
|
|
111
|
+
# ------------------------------------------------------------
|
|
112
|
+
CONTRACT_CODE = """
|
|
113
|
+
// SPDX-License-Identifier: GPL-3.0
|
|
114
|
+
pragma solidity >=0.8.2 <0.9.0;
|
|
115
|
+
|
|
116
|
+
contract AddTwoNumbers {
|
|
117
|
+
// Function to add two numbers and return the result
|
|
118
|
+
function add(uint256 a, uint256 b) public pure returns (uint256) {
|
|
119
|
+
return a + b;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
# ------------------------------------------------------------
|
|
125
|
+
# OUTPUT
|
|
126
|
+
# ------------------------------------------------------------
|
|
127
|
+
# The contract compiles and deploys successfully in Remix IDE.
|
|
128
|
+
# Calling add(5, 3) returns: 8
|
|
129
|
+
''')
|
|
130
|
+
|
|
131
|
+
def prac3():
|
|
132
|
+
return _show('''# Practical No. 3
|
|
133
|
+
# Aim: Configuring and Running a Hyperledger Fabric Network
|
|
134
|
+
|
|
135
|
+
# ------------------------------------------------------------
|
|
136
|
+
# SETUP / INSTALLATION STEPS (Windows users go through WSL first)
|
|
137
|
+
# ------------------------------------------------------------
|
|
138
|
+
|
|
139
|
+
# Step 1: Enable WSL2 on Windows (skip if using native Linux/Mac)
|
|
140
|
+
# Open PowerShell as Administrator and run:
|
|
141
|
+
wsl --install
|
|
142
|
+
# This installs WSL2 and Ubuntu by default. Restart your machine when prompted.
|
|
143
|
+
# Reference: https://learn.microsoft.com/en-us/windows/wsl/install
|
|
144
|
+
# If WSL is already installed, make sure it is on version 2:
|
|
145
|
+
wsl --set-default-version 2
|
|
146
|
+
# To install a specific Ubuntu version:
|
|
147
|
+
wsl --install -d Ubuntu-22.04
|
|
148
|
+
|
|
149
|
+
# Step 2: Install Docker Desktop
|
|
150
|
+
# Download from: https://www.docker.com/products/docker-desktop/
|
|
151
|
+
# During/after install, open Docker Desktop -> Settings -> Resources -> WSL Integration
|
|
152
|
+
# and enable integration with your Ubuntu distro. Docker Compose ships bundled with it.
|
|
153
|
+
# Verify inside the Ubuntu (WSL) terminal:
|
|
154
|
+
docker --version
|
|
155
|
+
docker compose version
|
|
156
|
+
|
|
157
|
+
# Step 3: Update packages and install prerequisites inside Ubuntu/WSL
|
|
158
|
+
sudo apt-get update
|
|
159
|
+
sudo apt-get install -y curl git build-essential
|
|
160
|
+
|
|
161
|
+
# Step 4: Install Go (required by some Fabric components)
|
|
162
|
+
# Download the Linux tarball from: https://go.dev/dl/
|
|
163
|
+
wget https://go.dev/dl/go1.21.0.linux-amd64.tar.gz
|
|
164
|
+
sudo tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz
|
|
165
|
+
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
|
|
166
|
+
source ~/.bashrc
|
|
167
|
+
go version
|
|
168
|
+
|
|
169
|
+
# Step 5: Install Node.js and npm inside Ubuntu/WSL
|
|
170
|
+
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
|
|
171
|
+
sudo apt-get install -y nodejs
|
|
172
|
+
node -v
|
|
173
|
+
|
|
174
|
+
# Step 6: Install Java (default-jdk) - needed for Java chaincode/tests
|
|
175
|
+
sudo apt-get install -y default-jdk
|
|
176
|
+
java -version
|
|
177
|
+
|
|
178
|
+
# Step 7: Download Hyperledger Fabric binaries, Docker images, and samples
|
|
179
|
+
# Official bootstrap script (installs fabric-samples, binaries, and docker images):
|
|
180
|
+
curl -sSLO https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/bootstrap.sh
|
|
181
|
+
chmod +x bootstrap.sh
|
|
182
|
+
./bootstrap.sh
|
|
183
|
+
# This creates a "fabric-samples" folder containing "test-network", "fabcar", etc.
|
|
184
|
+
|
|
185
|
+
# Step 8: Bring up the test network
|
|
186
|
+
cd fabric-samples/test-network
|
|
187
|
+
./network.sh up
|
|
188
|
+
|
|
189
|
+
# Step 9: Create a channel between organizations
|
|
190
|
+
./network.sh createChannel
|
|
191
|
+
|
|
192
|
+
# Step 10: Tear the network down when done
|
|
193
|
+
./network.sh down
|
|
194
|
+
|
|
195
|
+
# ------------------------------------------------------------
|
|
196
|
+
# THEORY
|
|
197
|
+
# ------------------------------------------------------------
|
|
198
|
+
# Hyperledger Fabric is a permissioned blockchain framework designed for
|
|
199
|
+
# enterprise use, supporting private channels and pluggable consensus.
|
|
200
|
+
# The fabric-samples/test-network directory provides a script, network.sh,
|
|
201
|
+
# to bring the network up, create channels, and tear it down.
|
|
202
|
+
|
|
203
|
+
# ------------------------------------------------------------
|
|
204
|
+
# OUTPUT
|
|
205
|
+
# ------------------------------------------------------------
|
|
206
|
+
# The network starts successfully with peer and orderer containers running,
|
|
207
|
+
# and a channel is created between the organizations.
|
|
208
|
+
# Run "docker ps" to confirm containers such as peer0.org1.example.com,
|
|
209
|
+
# peer0.org2.example.com, and orderer.example.com are up.
|
|
210
|
+
''')
|
|
211
|
+
|
|
212
|
+
def prac4():
|
|
213
|
+
return _show('''# Practical No. 4
|
|
214
|
+
# Aim: Storing and Retrieving Data Using IPFS
|
|
215
|
+
|
|
216
|
+
# ------------------------------------------------------------
|
|
217
|
+
# SETUP / INSTALLATION STEPS
|
|
218
|
+
# ------------------------------------------------------------
|
|
219
|
+
|
|
220
|
+
# Step 1: Download go-ipfs (Kubo) for your platform
|
|
221
|
+
# Get the latest release list from: https://dist.ipfs.tech/#go-ipfs
|
|
222
|
+
# Example for Linux amd64:
|
|
223
|
+
wget https://dist.ipfs.io/go-ipfs/v0.21.0/go-ipfs_v0.21.0_linux-amd64.tar.gz
|
|
224
|
+
|
|
225
|
+
# Step 2: Extract the archive
|
|
226
|
+
tar -xvzf go-ipfs_v0.21.0_linux-amd64.tar.gz
|
|
227
|
+
cd go-ipfs
|
|
228
|
+
|
|
229
|
+
# Step 3: Run the install script (copies the ipfs binary to /usr/local/bin)
|
|
230
|
+
sudo bash install.sh
|
|
231
|
+
|
|
232
|
+
# Step 4: Verify installation
|
|
233
|
+
ipfs --version
|
|
234
|
+
|
|
235
|
+
# Step 5: Initialize the local IPFS repository (one-time setup)
|
|
236
|
+
ipfs init
|
|
237
|
+
|
|
238
|
+
# Step 6: Start the IPFS daemon (keep this running in its own terminal)
|
|
239
|
+
ipfs daemon
|
|
240
|
+
|
|
241
|
+
# Step 7: In a new terminal, create and store a file on IPFS
|
|
242
|
+
echo "This is an example file to store on IPFS." > example.txt
|
|
243
|
+
ipfs add example.txt
|
|
244
|
+
|
|
245
|
+
# Step 8: Retrieve the file using its returned content hash (CID)
|
|
246
|
+
ipfs cat <CID_FROM_STEP_7>
|
|
247
|
+
|
|
248
|
+
# ------------------------------------------------------------
|
|
249
|
+
# THEORY
|
|
250
|
+
# ------------------------------------------------------------
|
|
251
|
+
# IPFS is a peer-to-peer distributed file system that stores data using
|
|
252
|
+
# content-based addressing instead of location-based addressing.
|
|
253
|
+
# Each file is identified by a unique cryptographic hash (CID), and any
|
|
254
|
+
# change to the file content produces a new hash.
|
|
255
|
+
# Core commands:
|
|
256
|
+
# - ipfs init : initializes the local IPFS repository
|
|
257
|
+
# - ipfs daemon : starts the IPFS node
|
|
258
|
+
# - ipfs add <file> : uploads a file and returns its content hash
|
|
259
|
+
# This makes IPFS useful for tamper-proof, decentralized storage that can
|
|
260
|
+
# be referenced from blockchain smart contracts.
|
|
261
|
+
|
|
262
|
+
# ------------------------------------------------------------
|
|
263
|
+
# OUTPUT
|
|
264
|
+
# ------------------------------------------------------------
|
|
265
|
+
# added QmXo9...k3F4 example.txt
|
|
266
|
+
# The returned hash (CID) can be used to retrieve the file from any IPFS node.
|
|
267
|
+
''')
|
|
268
|
+
|
|
269
|
+
def prac5():
|
|
270
|
+
return _show('''# Practical No. 5
|
|
271
|
+
# Aim: Using Blockchain to Ensure Data Integrity in ML Models
|
|
272
|
+
|
|
273
|
+
# ------------------------------------------------------------
|
|
274
|
+
# SETUP STEPS (uses Remix IDE - same environment as Practical 2)
|
|
275
|
+
# ------------------------------------------------------------
|
|
276
|
+
# Step 1: Open https://remix.ethereum.org
|
|
277
|
+
# Step 2: Create a new file "MLDataRegistry.sol" and paste the code below
|
|
278
|
+
# Step 3: Compile it in the "Solidity Compiler" tab
|
|
279
|
+
# Step 4: Deploy it under "Deploy & Run Transactions" using Remix VM
|
|
280
|
+
# Step 5: Call uploadDataset(<hash>) first, then registerModel(...), then getDataset(<hash>)
|
|
281
|
+
|
|
282
|
+
# ------------------------------------------------------------
|
|
283
|
+
# THEORY
|
|
284
|
+
# ------------------------------------------------------------
|
|
285
|
+
# The goal is to make ML models and their training data tamper-proof,
|
|
286
|
+
# transparent, and auditable by:
|
|
287
|
+
# - Ensuring training data has not been tampered with
|
|
288
|
+
# - Verifying model provenance: who trained it, when, and on what data
|
|
289
|
+
# - Making predictions auditable and traceable
|
|
290
|
+
# This is achieved by storing cryptographic hashes of datasets and models
|
|
291
|
+
# on-chain, rather than the raw data itself, keeping storage costs low
|
|
292
|
+
# while preserving verifiability.
|
|
293
|
+
|
|
294
|
+
# ------------------------------------------------------------
|
|
295
|
+
# CODE (Solidity)
|
|
296
|
+
# ------------------------------------------------------------
|
|
297
|
+
CONTRACT_CODE = """
|
|
298
|
+
// SPDX-License-Identifier: GPL-3.0
|
|
299
|
+
pragma solidity >=0.8.2 <0.9.0;
|
|
300
|
+
|
|
301
|
+
contract MLDataRegistry {
|
|
302
|
+
struct Dataset {
|
|
303
|
+
string dataHash;
|
|
304
|
+
address uploader;
|
|
305
|
+
uint timestamp;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
struct MLModel {
|
|
309
|
+
string modelHash;
|
|
310
|
+
string dataHash;
|
|
311
|
+
string metrics;
|
|
312
|
+
address trainer;
|
|
313
|
+
uint timestamp;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
mapping(string => Dataset) public datasets;
|
|
317
|
+
mapping(string => MLModel) public models;
|
|
318
|
+
|
|
319
|
+
event DatasetUploaded(string dataHash, address uploader, uint timestamp);
|
|
320
|
+
event ModelTrained(string modelHash, string dataHash, string metrics, address trainer, uint timestamp);
|
|
321
|
+
|
|
322
|
+
function uploadDataset(string memory _dataHash) public {
|
|
323
|
+
require(bytes(_dataHash).length > 0, "Invalid hash");
|
|
324
|
+
datasets[_dataHash] = Dataset(_dataHash, msg.sender, block.timestamp);
|
|
325
|
+
emit DatasetUploaded(_dataHash, msg.sender, block.timestamp);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function registerModel(string memory _modelHash, string memory _dataHash, string memory _metrics) public {
|
|
329
|
+
require(datasets[_dataHash].timestamp != 0, "Dataset must be uploaded first");
|
|
330
|
+
models[_modelHash] = MLModel(_modelHash, _dataHash, _metrics, msg.sender, block.timestamp);
|
|
331
|
+
emit ModelTrained(_modelHash, _dataHash, _metrics, msg.sender, block.timestamp);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function getDataset(string memory _dataHash) public view returns (Dataset memory) {
|
|
335
|
+
return datasets[_dataHash];
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
"""
|
|
339
|
+
|
|
340
|
+
# ------------------------------------------------------------
|
|
341
|
+
# OUTPUT
|
|
342
|
+
# ------------------------------------------------------------
|
|
343
|
+
# uploadDataset("9a0364b9e99bb...c9fefb0")
|
|
344
|
+
# getDataset("9a0364b9e99bb...c9fefb0") returns:
|
|
345
|
+
# {
|
|
346
|
+
# "dataHash": "9a0364b9e99bb...c9fefb0",
|
|
347
|
+
# "uploader": "0xAbC1234...7890",
|
|
348
|
+
# "timestamp": 1717420217
|
|
349
|
+
# }
|
|
350
|
+
''')
|
|
351
|
+
|
|
352
|
+
def prac6():
|
|
353
|
+
return _show('''# Practical No. 6
|
|
354
|
+
# Aim: Implementing a Blockchain-Based Data Provenance System
|
|
355
|
+
|
|
356
|
+
# ------------------------------------------------------------
|
|
357
|
+
# SETUP STEPS (uses Remix IDE - same environment as Practical 2)
|
|
358
|
+
# ------------------------------------------------------------
|
|
359
|
+
# Step 1: Open https://remix.ethereum.org
|
|
360
|
+
# Step 2: Create "DataProvenance.sol" and paste the code below
|
|
361
|
+
# Step 3: Compile, then deploy using Remix VM
|
|
362
|
+
# Step 4: Call logData("file1", "<hash>") one or more times
|
|
363
|
+
# Step 5: Call getProvenance("file1") to view the full history
|
|
364
|
+
|
|
365
|
+
# ------------------------------------------------------------
|
|
366
|
+
# THEORY
|
|
367
|
+
# ------------------------------------------------------------
|
|
368
|
+
# Data provenance refers to tracking the origin and history of a piece of
|
|
369
|
+
# data over time. For each data entry, the system records:
|
|
370
|
+
# - The data hash
|
|
371
|
+
# - Who logged it (owner address)
|
|
372
|
+
# - When it was logged (timestamp)
|
|
373
|
+
# This is useful for verifying data authenticity and ownership over time,
|
|
374
|
+
# and provides an immutable audit trail for compliance and traceability.
|
|
375
|
+
|
|
376
|
+
# ------------------------------------------------------------
|
|
377
|
+
# CODE (Solidity)
|
|
378
|
+
# ------------------------------------------------------------
|
|
379
|
+
CONTRACT_CODE = """
|
|
380
|
+
// SPDX-License-Identifier: GPL-3.0
|
|
381
|
+
pragma solidity >=0.8.2 <0.9.0;
|
|
382
|
+
|
|
383
|
+
contract DataProvenance {
|
|
384
|
+
struct DataEntry {
|
|
385
|
+
string dataHash;
|
|
386
|
+
address owner;
|
|
387
|
+
uint256 timestamp;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
mapping(string => DataEntry[]) public provenanceRecords;
|
|
391
|
+
|
|
392
|
+
event DataLogged(string dataId, string dataHash, address indexed owner, uint256 timestamp);
|
|
393
|
+
|
|
394
|
+
function logData(string memory dataId, string memory dataHash) public {
|
|
395
|
+
DataEntry memory entry = DataEntry(dataHash, msg.sender, block.timestamp);
|
|
396
|
+
provenanceRecords[dataId].push(entry);
|
|
397
|
+
emit DataLogged(dataId, dataHash, msg.sender, block.timestamp);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function getProvenance(string memory dataId) public view returns (DataEntry[] memory) {
|
|
401
|
+
return provenanceRecords[dataId];
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
"""
|
|
405
|
+
|
|
406
|
+
# ------------------------------------------------------------
|
|
407
|
+
# OUTPUT
|
|
408
|
+
# ------------------------------------------------------------
|
|
409
|
+
# logData("file1", "9a0364b9...") successfully appends a new provenance record.
|
|
410
|
+
# getProvenance("file1") returns the full history of entries for that data ID.
|
|
411
|
+
''')
|
|
412
|
+
|
|
413
|
+
def prac7():
|
|
414
|
+
return _show('''# Practical No. 7
|
|
415
|
+
# Aim: Developing a Decentralized Marketplace for Data Exchange
|
|
416
|
+
|
|
417
|
+
# ------------------------------------------------------------
|
|
418
|
+
# SETUP STEPS (uses Remix IDE - same environment as Practical 2)
|
|
419
|
+
# ------------------------------------------------------------
|
|
420
|
+
# Step 1: Open https://remix.ethereum.org
|
|
421
|
+
# Step 2: Create "VotingForTopper.sol" and paste the code below
|
|
422
|
+
# Step 3: Compile, then deploy using Remix VM with the first account as owner
|
|
423
|
+
# Step 4: Call authorize(<address>) as the owner to whitelist a voter
|
|
424
|
+
# Step 5: Call teamAF(<address>) from an authorized account to cast a vote
|
|
425
|
+
# Step 6: Call resultOfVoting() to view the current standings
|
|
426
|
+
|
|
427
|
+
# ------------------------------------------------------------
|
|
428
|
+
# THEORY
|
|
429
|
+
# ------------------------------------------------------------
|
|
430
|
+
# A decentralized marketplace/exchange relies on smart contracts to
|
|
431
|
+
# coordinate participant actions transparently, without a central
|
|
432
|
+
# intermediary. This practical demonstrates the underlying pattern using
|
|
433
|
+
# a voting contract, where:
|
|
434
|
+
# - Only the owner can authorize participants
|
|
435
|
+
# - Authorized participants can cast one vote each
|
|
436
|
+
# - Results are computed transparently on-chain
|
|
437
|
+
# The same access-control and state-tracking pattern (authorize -> act
|
|
438
|
+
# once -> view result) generalizes to marketplace listings, bids, and
|
|
439
|
+
# settlement.
|
|
440
|
+
|
|
441
|
+
# ------------------------------------------------------------
|
|
442
|
+
# CODE (Solidity)
|
|
443
|
+
# ------------------------------------------------------------
|
|
444
|
+
CONTRACT_CODE = """
|
|
445
|
+
pragma solidity 0.8.17;
|
|
446
|
+
|
|
447
|
+
contract VotingForTopper {
|
|
448
|
+
address owner;
|
|
449
|
+
string public purpose;
|
|
450
|
+
|
|
451
|
+
struct Voter {
|
|
452
|
+
bool authorized;
|
|
453
|
+
bool voted;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
uint totalVotes;
|
|
457
|
+
uint teamA;
|
|
458
|
+
uint teamB;
|
|
459
|
+
uint teamC;
|
|
460
|
+
|
|
461
|
+
mapping(address => Voter) info;
|
|
462
|
+
|
|
463
|
+
constructor(string memory _name) {
|
|
464
|
+
purpose = _name;
|
|
465
|
+
owner = msg.sender;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
modifier ownerOn() {
|
|
469
|
+
require(msg.sender == owner);
|
|
470
|
+
_;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function authorize(address _person) public ownerOn {
|
|
474
|
+
info[_person].authorized = true;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function teamAF(address _address) public {
|
|
478
|
+
require(!info[_address].voted, "already voted");
|
|
479
|
+
require(info[_address].authorized, "not authorized");
|
|
480
|
+
info[_address].voted = true;
|
|
481
|
+
teamA++;
|
|
482
|
+
totalVotes++;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function resultOfVoting() public view returns (string memory) {
|
|
486
|
+
if (teamA > teamB && teamA > teamC) return "A is Winning";
|
|
487
|
+
if (teamB > teamA && teamB > teamC) return "B is Winning";
|
|
488
|
+
return "No One is Winning";
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
"""
|
|
492
|
+
|
|
493
|
+
# ------------------------------------------------------------
|
|
494
|
+
# OUTPUT
|
|
495
|
+
# ------------------------------------------------------------
|
|
496
|
+
# Deploying with address 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4,
|
|
497
|
+
# authorizing an account, then casting a vote updates totalVotes and
|
|
498
|
+
# resultOfVoting() reflects the current standings.
|
|
499
|
+
''')
|
|
500
|
+
|
|
501
|
+
def prac8():
|
|
502
|
+
return _show('''# Practical No. 8
|
|
503
|
+
# Aim: Writing and Deploying Chaincode on Hyperledger Fabric
|
|
504
|
+
|
|
505
|
+
# ------------------------------------------------------------
|
|
506
|
+
# SETUP / INSTALLATION STEPS
|
|
507
|
+
# (Requires the Practical 3 environment already set up: WSL, Docker,
|
|
508
|
+
# Go, Node.js, Java, and fabric-samples downloaded)
|
|
509
|
+
# ------------------------------------------------------------
|
|
510
|
+
|
|
511
|
+
# Step 1: Stop any previously running network (clean slate)
|
|
512
|
+
cd fabric-samples/test-network
|
|
513
|
+
./network.sh down
|
|
514
|
+
|
|
515
|
+
# Step 2: Navigate to the FabCar sample application
|
|
516
|
+
cd ../fabcar
|
|
517
|
+
|
|
518
|
+
# Step 3: Launch the FabCar network (spins up test-network + installs chaincode)
|
|
519
|
+
./startFabric.sh javascript
|
|
520
|
+
|
|
521
|
+
# Step 4: Move into the JavaScript client application folder and install dependencies
|
|
522
|
+
cd javascript
|
|
523
|
+
npm install
|
|
524
|
+
|
|
525
|
+
# Step 5: Enroll the admin identity with the Certificate Authority
|
|
526
|
+
node enrollAdmin.js
|
|
527
|
+
|
|
528
|
+
# Step 6: Register and enroll an application user (appUser)
|
|
529
|
+
node registerUser.js
|
|
530
|
+
|
|
531
|
+
# Step 7: Query the ledger to list all cars currently recorded
|
|
532
|
+
node query.js
|
|
533
|
+
|
|
534
|
+
# Step 8: Submit a transaction to create a new car (edit invoke.js accordingly)
|
|
535
|
+
# invoke.js snippet:
|
|
536
|
+
# await contract.submitTransaction('createCar', 'CAR12', 'Honda', 'Accord', 'Black', 'Tom');
|
|
537
|
+
node invoke.js
|
|
538
|
+
|
|
539
|
+
# Step 9: Transfer ownership of the car (edit invoke.js accordingly)
|
|
540
|
+
# invoke.js snippet:
|
|
541
|
+
# await contract.submitTransaction('changeCarOwner', 'CAR12', 'Dave');
|
|
542
|
+
node invoke.js
|
|
543
|
+
|
|
544
|
+
# Step 10: Query again to confirm the update was committed
|
|
545
|
+
node query.js
|
|
546
|
+
|
|
547
|
+
# ------------------------------------------------------------
|
|
548
|
+
# THEORY
|
|
549
|
+
# ------------------------------------------------------------
|
|
550
|
+
# Chaincode is Fabric's term for smart contracts - programs that define
|
|
551
|
+
# the rules for reading and updating the shared ledger.
|
|
552
|
+
# The FabCar sample demonstrates a typical chaincode workflow:
|
|
553
|
+
# - Enroll admin and application user identities with the Certificate Authority
|
|
554
|
+
# - query.js reads the current world state (list of cars) from the ledger
|
|
555
|
+
# - invoke.js submits transactions such as createCar and changeCarOwner
|
|
556
|
+
# Each update goes through the consensus process before being committed,
|
|
557
|
+
# ensuring all peers agree on the new ledger state.
|
|
558
|
+
|
|
559
|
+
# ------------------------------------------------------------
|
|
560
|
+
# OUTPUT
|
|
561
|
+
# ------------------------------------------------------------
|
|
562
|
+
# query.js lists all cars currently on the ledger.
|
|
563
|
+
# invoke.js createCar adds CAR12 (Honda Accord, owner Tom).
|
|
564
|
+
# invoke.js changeCarOwner transfers CAR12 to Dave after consensus is reached.
|
|
565
|
+
''')
|
|
566
|
+
|
|
567
|
+
def prac9():
|
|
568
|
+
return _show('''# Practical No. 9
|
|
569
|
+
# Aim: Implementing a Secure Voting System Using Blockchain
|
|
570
|
+
|
|
571
|
+
# ------------------------------------------------------------
|
|
572
|
+
# SETUP STEPS (uses Remix IDE - same environment/contract as Practical 7)
|
|
573
|
+
# ------------------------------------------------------------
|
|
574
|
+
# Step 1: Open https://remix.ethereum.org and reuse/redeploy VotingForTopper.sol
|
|
575
|
+
# Step 2: Deploy using the first account (this becomes the contract owner)
|
|
576
|
+
# Step 3: Call authorize(<address>) to whitelist a voter
|
|
577
|
+
# Step 4: Call teamAF(<address>) to cast a vote for Team A
|
|
578
|
+
# Step 5: Call resultOfVoting() to confirm it reflects the current standings
|
|
579
|
+
|
|
580
|
+
# ------------------------------------------------------------
|
|
581
|
+
# THEORY
|
|
582
|
+
# ------------------------------------------------------------
|
|
583
|
+
# A blockchain-based voting system uses smart contracts to guarantee
|
|
584
|
+
# transparency and prevent double voting or tampering.
|
|
585
|
+
# Security is enforced through:
|
|
586
|
+
# - An owner-only modifier restricting who can authorize voters
|
|
587
|
+
# - A "voted" flag preventing any address from voting more than once
|
|
588
|
+
# - Public, auditable vote counts and result computation
|
|
589
|
+
# Because the contract logic and all transactions are recorded immutably
|
|
590
|
+
# on-chain, the final result can be independently verified by anyone.
|
|
591
|
+
|
|
592
|
+
# ------------------------------------------------------------
|
|
593
|
+
# CODE (Solidity - core voting logic)
|
|
594
|
+
# ------------------------------------------------------------
|
|
595
|
+
CONTRACT_CODE = """
|
|
596
|
+
function authorize(address _person) public ownerOn {
|
|
597
|
+
info[_person].authorized = true;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
function teamAF(address _address) public {
|
|
601
|
+
require(!info[_address].voted, "already voted");
|
|
602
|
+
require(info[_address].authorized, "not authorized");
|
|
603
|
+
info[_address].voted = true;
|
|
604
|
+
teamA++;
|
|
605
|
+
totalVotes++;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function resultOfVoting() public view returns (string memory) {
|
|
609
|
+
if (teamA > teamB && teamA > teamC) return "A is Winning";
|
|
610
|
+
if (teamB > teamA && teamB > teamC) return "B is Winning";
|
|
611
|
+
if (teamC > teamA && teamC > teamB) return "C is Winning";
|
|
612
|
+
return "No One is Winning";
|
|
613
|
+
}
|
|
614
|
+
"""
|
|
615
|
+
|
|
616
|
+
# ------------------------------------------------------------
|
|
617
|
+
# OUTPUT
|
|
618
|
+
# ------------------------------------------------------------
|
|
619
|
+
# After authorizing an account and casting a vote for Team A,
|
|
620
|
+
# resultOfVoting() correctly returns "A is Winning".
|
|
621
|
+
''')
|
|
622
|
+
|
|
623
|
+
def prac10():
|
|
624
|
+
return _show('''# Practical No. 10
|
|
625
|
+
# Aim: Combining Blockchain with IoT for Secure Data Management
|
|
626
|
+
|
|
627
|
+
# NOTE: The source practical book covers this topic at the theory level
|
|
628
|
+
# only (concepts and benefits) without a worked code example. The
|
|
629
|
+
# implementation below is a representative, runnable example built in
|
|
630
|
+
# the same spirit as Practicals 5/6 (hash-based on-chain registry),
|
|
631
|
+
# applied here to IoT device readings.
|
|
632
|
+
|
|
633
|
+
# ------------------------------------------------------------
|
|
634
|
+
# SETUP STEPS (uses Remix IDE - same environment as Practical 2)
|
|
635
|
+
# ------------------------------------------------------------
|
|
636
|
+
# Step 1: Open https://remix.ethereum.org
|
|
637
|
+
# Step 2: Create "IoTDataRegistry.sol" and paste the contract code below
|
|
638
|
+
# Step 3: Compile, then deploy using Remix VM
|
|
639
|
+
# Step 4: Call registerDevice(<deviceId>) once per device
|
|
640
|
+
# Step 5: Call logReading(<deviceId>, <dataHash>) each time a device reports data
|
|
641
|
+
# Step 6: Call getLatestReading(<deviceId>) to fetch the most recent tamper-proof record
|
|
642
|
+
|
|
643
|
+
# ------------------------------------------------------------
|
|
644
|
+
# THEORY
|
|
645
|
+
# ------------------------------------------------------------
|
|
646
|
+
# Blockchain and IoT integration combines a secure, decentralized ledger
|
|
647
|
+
# with connected devices to enhance trust, automation, and security.
|
|
648
|
+
# Blockchain is used to manage and record IoT device interactions,
|
|
649
|
+
# ensuring data integrity, trustless communication, automation via smart
|
|
650
|
+
# contracts, and secure access control.
|
|
651
|
+
# Benefits:
|
|
652
|
+
# - Tamper-proof logs and records of device data
|
|
653
|
+
# - Secure device-to-device communication
|
|
654
|
+
# - Transparent auditing of events
|
|
655
|
+
# - Reduced operational costs through automation
|
|
656
|
+
# - Enhanced automation via smart-contract-triggered actions
|
|
657
|
+
|
|
658
|
+
# ------------------------------------------------------------
|
|
659
|
+
# CODE (Solidity)
|
|
660
|
+
# ------------------------------------------------------------
|
|
661
|
+
CONTRACT_CODE = """
|
|
662
|
+
// SPDX-License-Identifier: GPL-3.0
|
|
663
|
+
pragma solidity >=0.8.2 <0.9.0;
|
|
664
|
+
|
|
665
|
+
contract IoTDataRegistry {
|
|
666
|
+
struct Reading {
|
|
667
|
+
string dataHash;
|
|
668
|
+
uint256 timestamp;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
mapping(string => bool) public registeredDevices;
|
|
672
|
+
mapping(string => Reading) public latestReading;
|
|
673
|
+
|
|
674
|
+
event DeviceRegistered(string deviceId);
|
|
675
|
+
event ReadingLogged(string deviceId, string dataHash, uint256 timestamp);
|
|
676
|
+
|
|
677
|
+
function registerDevice(string memory deviceId) public {
|
|
678
|
+
registeredDevices[deviceId] = true;
|
|
679
|
+
emit DeviceRegistered(deviceId);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function logReading(string memory deviceId, string memory dataHash) public {
|
|
683
|
+
require(registeredDevices[deviceId], "Device not registered");
|
|
684
|
+
latestReading[deviceId] = Reading(dataHash, block.timestamp);
|
|
685
|
+
emit ReadingLogged(deviceId, dataHash, block.timestamp);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
function getLatestReading(string memory deviceId) public view returns (Reading memory) {
|
|
689
|
+
return latestReading[deviceId];
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
"""
|
|
693
|
+
|
|
694
|
+
# ------------------------------------------------------------
|
|
695
|
+
# OUTPUT
|
|
696
|
+
# ------------------------------------------------------------
|
|
697
|
+
# registerDevice("sensor-01")
|
|
698
|
+
# logReading("sensor-01", "9a0364b9e99bb...c9fefb0")
|
|
699
|
+
# getLatestReading("sensor-01") returns:
|
|
700
|
+
# {
|
|
701
|
+
# "dataHash": "9a0364b9e99bb...c9fefb0",
|
|
702
|
+
# "timestamp": 1717420217
|
|
703
|
+
# }
|
|
704
|
+
''')
|
|
705
|
+
|
|
706
|
+
PRACTICALS = {
|
|
707
|
+
1: prac1, 2: prac2, 3: prac3, 4: prac4,
|
|
708
|
+
5: prac5, 6: prac6, 7: prac7, 8: prac8,
|
|
709
|
+
9: prac9, 10: prac10,
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
def get_practical(n: int) -> str:
|
|
713
|
+
"""Print and return code for practical n (1-10)."""
|
|
714
|
+
if n not in PRACTICALS:
|
|
715
|
+
raise ValueError(f"BC has practicals 1-10, got {n}")
|
|
716
|
+
return PRACTICALS[n]()
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
__all__ = [
|
|
720
|
+
"prac1", "prac2", "prac3", "prac4", "prac5",
|
|
721
|
+
"prac6", "prac7", "prac8", "prac9", "prac10",
|
|
722
|
+
"get_practical", "PRACTICALS", "__version__",
|
|
723
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: semfnode
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Kelp harvest scheduling utilities for coastal tide pools
|
|
5
5
|
Author: M. Holloway
|
|
6
6
|
License-Expression: MIT
|
|
@@ -16,4 +16,3 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
17
|
Classifier: Topic :: Scientific/Engineering :: Oceanography
|
|
18
18
|
Requires-Python: >=3.8
|
|
19
|
-
Description-Content-Type: text/markdown
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|