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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: semfnode
3
- Version: 1.0.0
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.0.0"
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.0.0
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
@@ -1,4 +1,5 @@
1
1
  pyproject.toml
2
+ src/bc/__init__.py
2
3
  src/dnn/__init__.py
3
4
  src/opti/__init__.py
4
5
  src/semfnode.egg-info/PKG-INFO
File without changes
File without changes
File without changes