Tag Archives: blockchain

Decentralized Identifiers (DIDs) as Barcodes for Secure, Trusted Digital Communication

Create your own magic with Web 7.0 Agentic OS. Imagine the possibilities.

Copyright © 2025 Michael Herman (Bindloss, Alberta, Canada) – Creative Commons Attribution-ShareAlike 4.0 International Public License

Abstract


The invention of the barcode transformed retail and supply chains by providing a universal, machine-readable identifier that ensured accuracy, efficiency, and interoperability across diverse systems. Similarly, Decentralized Identifiers (DIDs) represent a foundational innovation for digital ecosystems: a universal, cryptographically verifiable identifier that enables trusted communication across domains and platforms. This paper explores the analogy between DIDs and barcodes, examining how both enable end-to-end interoperability, reduce friction, and unlock new models of value creation.

Copyright © 2025 Michael Herman (Bindloss, Alberta, Canada) – Creative Commons Attribution-ShareAlike 4.0 International Public License


1. Introduction

In 1974, a pack of Wrigley’s gum was scanned at a Marsh supermarket in Ohio, marking the first use of the Universal Product Code (UPC). That moment marked the beginning of a transformation in retail, logistics, and global commerce. By providing a standardized identifier, barcodes automated inventory management, accelerated checkout, reduced human error, and laid the foundation for today’s global supply chains.

Digital ecosystems in the 21st century face an equivalent problem: how to create universal, secure, and machine-readable identifiers that work across organizations, platforms, and jurisdictions. While domain names, IP addresses, and UUIDs serve as identifiers, none are self-sovereign, portable, and verifiable across trust boundaries. Decentralized Identifiers (DIDs) aim to solve this.

This paper argues that DIDs are the barcodes of digital trust: a universal, machine-readable system for identifying entities in secure communications, enabling a new end-to-end supply chain of digital trust.


2. The Barcode Revolution

2.1 Before Barcodes

  • Manual price tags and clerical data entry.
  • Inventory tracking prone to human error.
  • Inefficient supply chains with frequent stockouts and overstocking.
  • Lack of standardization across retailers and manufacturers.

2.2 With Barcodes

  • Universal identifiers: UPC and EAN standards.
  • Machine readability: fast, automated scanning reduced labor costs and errors.
  • End-to-end traceability: from manufacturer → distributor → retailer → checkout.
  • Scalability: millions of products, billions of transactions.

Impact: Barcodes enabled just-in-time inventory, global retail expansion, and precise supply chain optimization [Brown, Inventing the Barcode, 2010]. The key insight: a universal, interoperable identifier unlocks systemic efficiencies across the value chain.


3. DIDs: A Digital Barcode for Trust

3.1 What are DIDs?

Decentralized Identifiers (DIDs) are globally unique identifiers that are self-sovereign, verifiable, and resolvable without reliance on centralized registries. Defined by the W3C, DIDs point to DID Documents, which contain public keys, service endpoints, and metadata necessary for establishing secure communication.

3.2 Core Features

  • Universality: A DID can represent a person, organization, device, or digital asset.
  • Machine readability: DIDs are structured and resolvable by software.
  • Cryptographic trust: Integrity and authenticity are verifiable through signatures and key material.
  • Decentralization: No single issuing authority required; anyone can create a DID.
  • Extensibility: Support for multiple DID methods (blockchain, ledger, peer-to-peer).

3.3 Why It Matters

Just as barcodes freed retail from manual, siloed processes, DIDs free digital ecosystems from centralized identity silos (e.g., social logins, proprietary identity providers).


4. Mapping the Analogy: Barcodes vs. DIDs

Barcode PropertyDID EquivalentImplications
Universal product identifierUniversal decentralized identifierEnables global recognition of digital actors
Machine-readableMachine-resolvable DID DocumentAutomated verification by software agents
Standardization (UPC/EAN)W3C DID Core standardCross-platform interoperability
Scannable at every point in supply chainResolvable across trust domainsEnd-to-end verifiable identity
Facilitates inventory managementFacilitates trust managementEnsures secure digital transactions
Enables retail efficiencyEnables digital trust ecosystemsReduces cost, friction, and fraud

5. Benefits of the Barcode Analogy

  1. End-to-End Traceability
    • Barcodes track goods from origin to checkout.
    • DIDs enable trust from authentication through data exchange to audit.
  2. Automation and Efficiency
    • Barcodes eliminated manual entry; DIDs eliminate manual trust establishment.
  3. Interoperability
    • Any barcode scanner can read a UPC; any DID-compliant system can resolve a DID.
  4. Scalability
    • Barcodes scaled to billions of products; DIDs can scale to billions of devices, people, and services.
  5. Systemic Transformation
    • Barcodes reshaped retail; DIDs could reshape finance, healthcare, IoT, and governance.

6. Limits of the Analogy

  • Centralization vs. Decentralization: Barcodes are managed by centralized registries (GS1), whereas DIDs are inherently decentralized.
  • Trust Layer: Barcodes encode only identity (the product number), not integrity or authenticity. DIDs add cryptographic verifiability.
  • Complexity: Scanning a barcode is simpler than resolving a DID, which requires cryptographic operations and network lookups.
  • Adoption: Barcodes achieved rapid, global retail adoption; DIDs remain in early deployment phases.

7. Strategic Implications

7.1 Identity and Access

DIDs could serve as the UPC of digital identity, enabling universal, interoperable identity across organizations.

7.2 Supply Chain and IoT

DIDs can extend barcodes’ logic into digital-physical convergence, providing secure digital twins for physical assets.

7.3 Finance and Governance

DIDs provide the foundational layer of trust for verifiable credentials, smart contracts, and cross-border compliance.

7.4 The “Barcode Moment”

Just as retail only transformed once barcodes were widely adopted, the digital trust economy will require a tipping point of DID adoption to realize systemic benefits.


8. Conclusion

The barcode transformed retail by enabling universal, machine-readable product identification across the supply chain. DIDs can do the same for digital ecosystems by enabling universal, machine-readable, and verifiable identity.

If DIDs achieve broad adoption, they could serve as the universal identifiers of digital trust, enabling secure, scalable, and interoperable communication across the global digital economy — much as barcodes enabled the rise of global retail supply chains.


References


Inspired by the book Reshuffle by Sangeet Paul Choudary.

Produced as the outcome of a conversation between Michael Herman and ChatGPT. October 1, 2025.

1 Comment

Filed under Uncategorized

DIDComm Messages as the Steel Shipping Containers of Secure, Trusted Digital Communication

Create your own magic with Web 7.0 AgenticOS™. Imagine the possibilities.

Copyright © 2025 Michael Herman (Bindloss, Alberta, Canada) – Creative Commons Attribution-ShareAlike 4.0 International Public License

Abstract

The steel shipping container transformed global trade by introducing a standardized, secure, and interoperable abstraction for transporting goods. Similarly, Decentralized Identifier Communication (DIDComm) offers a standardized, secure, and interoperable mechanism for transmitting trusted digital information between agents. This paper explores the analogy between DIDComm messages and steel containers, examining their properties, benefits, and limitations, and assessing the potential of DIDComm to catalyze a transformation in digital ecosystems comparable to the shipping container revolution.

Copyright © 2025 Michael Herman (Bindloss, Alberta, Canada) – Creative Commons Attribution-ShareAlike 4.0 International Public License


1. Introduction

The 20th century witnessed a quiet revolution in global trade: the invention and adoption of the steel shipping container. More than faster ships or larger ports, it was standardization in how goods were packaged and transported that unlocked efficiency, scale, and global interoperability.

In the 21st century, digital ecosystems face a parallel challenge. Secure communication across heterogeneous systems remains fragmented by proprietary protocols, siloed trust frameworks, and inconsistent interoperability. Despite advances in transport protocols (HTTP, WebSocket, Bluetooth) and security primitives (TLS, OAuth, JWT), no universal standard exists for trusted, end-to-end, cross-domain messaging.

DIDComm (Decentralized Identifier Communication) aims to fill this gap. It provides a standardized envelope for secure, interoperable communication between agents in decentralized ecosystems. This paper argues that DIDComm can be understood as the steel shipping container of digital communication — a payload-agnostic, transport-agnostic, secure packaging standard that enables trust to move seamlessly across networks and domains.


2. The Shipping Container Revolution

2.1 Before Containers

  • Cargo packaged idiosyncratically: barrels, sacks, crates.
  • Loading/unloading labor-intensive and slow.
  • High rates of pilferage and damage.
  • Inefficiency in intermodal transport (ship → rail → truck required repackaging).

2.2 With Containers

  • ISO standardization: uniform sizes, fittings, and corner posts.
  • Sealed security: tamper-resistant, weatherproof units.
  • Stackability: efficient storage and loading by crane.
  • Interoperability: ships, ports, trucks, and trains adapted to a single form factor.

Impact: Containerization reduced costs by ~90% and increased the speed and scale of global trade [Levinson, The Box, 2006]. The key insight: decouple contents from infrastructure via a universal abstraction.


3. DIDComm: A Digital Container Standard

3.1 What is DIDComm?

DIDComm is a protocol suite for secure, private, and interoperable communication using Decentralized Identifiers (DIDs) as endpoints. It defines how messages are packaged, encrypted, authenticated, and routed between agents.

3.2 Core Features

  • Standardized envelope: headers, routing metadata, payload.
  • Cryptographic sealing: encryption (confidentiality), signatures (authenticity), checksums (integrity).
  • Transport agnosticism: works over HTTP, Bluetooth, WebRTC, email, etc.
  • Routing via mediators: messages can traverse multiple relays without breaking end-to-end security.
  • Payload agnosticism: the message may carry verifiable credentials, IoT commands, or arbitrary application data.

3.3 Why It Matters

Just as containers enabled intermodal trade, DIDComm enables intermodal trust exchange. Applications, wallets, devices, and services can interoperate without bespoke integrations.


4. Mapping the Analogy: Containers vs. DIDComm

Container PropertyDIDComm EquivalentImplications
Standardized formEnvelope with defined structure (headers, body, metadata)Guarantees interoperability across agents and vendors
Sealed & secureEncryption + authenticationProtects against unauthorized access and tampering
Intermodal transportTransport-agnostic deliveryWorks across protocols without altering the payload
Routing via logisticsMediators, DID resolution, forwardingEnables flexible message delivery
Opaque contentsEncrypted payloadOnly authorized parties can inspect
Global ecosystem supportAgent networks, wallets, identity hubsEmerging infrastructure could mirror global ports and carriers

5. Benefits of the Container Analogy

  1. Interoperability
    • Any DIDComm-compliant agent can process a message, just as any port can handle a container.
  2. Security and Trust
    • Messages are sealed like containers, with tamper-evident cryptography.
  3. Efficiency
    • Reduces the cost and complexity of building integrations across organizations.
  4. Scalability
    • Supports any type of payload: credentials, IoT signals, governance instructions.
  5. Decentralization
    • No reliance on a central authority; trust derives from cryptographic keys, similar to how container standards are managed by ISO, not controlled by one nation or corporation.

6. Limits of the Analogy

  • Physical persistence vs. digital ephemerality: Containers endure across voyages; messages vanish after delivery.
  • Metadata leakage: Container labels are visible; DIDComm may still expose sender/recipient metadata.
  • Standard stability: Container sizes have been stable for decades; DIDComm may evolve quickly.
  • Global adoption: Containerization achieved near-universal acceptance; DIDComm is still early in adoption.

7. Strategic Implications

7.1 Identity & Credentials

DIDComm provides a secure transport for verifiable credentials, enabling cross-border, cross-domain trust.

7.2 IoT Ecosystems

IoT devices require lightweight, trustable communication. DIDComm offers a containerized way to exchange secure commands.

7.3 Cross-Domain Interoperability

Applications in finance, healthcare, supply chains, and governance can exchange trusted data without bespoke APIs.

7.4 The “Container Moment”

Global trade was reshaped once container standards reached critical mass. DIDComm could catalyze a parallel moment in digital ecosystems if widely adopted.


8. Conclusion

The steel shipping container revolutionized trade by abstracting the packaging and transport of goods into a universal, secure standard. DIDComm has the potential to do the same for digital trust, abstracting communication into a universal, secure, and interoperable form.

If DIDComm achieves broad adoption, it could serve as the logistics backbone of the digital trust economy, enabling decentralized ecosystems to scale with the efficiency and security once brought to global commerce by steel containers.


References

  • Levinson, Marc. The Box: How the Shipping Container Made the World Smaller and the World Economy Bigger. Princeton University Press, 2006.
  • DIF (Decentralized Identity Foundation). “DIDComm Messaging Specification.” https://identity.foundation/didcomm-messaging.
  • Hardman, Daniel. “Introduction to DIDComm.” Hyperledger Aries Working Group, 2021.
  • ISO. “ISO 668: Series 1 freight containers — Classification, dimensions and ratings.”


Based on a discussion between Michael Herman and ChatGPT. September 30, 2025.

1 Comment

Filed under Uncategorized

Ethereum geth.exe Dashboard built with Nethereum

Here’s a screenshot of the current version of a dashboard that I’ve built for geth.exe using the Nethereum .NET integration libraries for Ethereum. (click the image to enlarge it).

mwherman200-geth-dashboard1

Yes, it is a .NET desktop WinForms client.

The app uses a background task to update the Node State section of the form on a timed interval.  It also knows how to send Ether (with or without extra data) between two accounts. The send Ether integration assumes you have more than one account configured in your Rinkeby geth.exe node.  The app will prompt for your password the first time it is required.

It also has direct integration with an existing deployment of the Ballot contract.  The Ballot integration assumes the existing contract address is on the Rinkeby Ethereum network.

In terms of failover, the app tests to see if geth.exe is running and will automatically connect (and reconnect) if geth.exe isn’t already running on Rinkeby.  It also checks to see if the node is syncing and if so, the background task pauses until the sync completes.

Enjoy,

Michael Herman (Toronto)

Leave a comment

Filed under .NET Development, blockchain, Ethereum, Nethereum

Ethereum .NET Development Examples using the Nethereum Integration Libraries

This is an early version of an article that is intended to help developers who have a basic knowledge of the Ethereum blockchain platform and want to learn how to program against the Ethereum platform using the Nethereum .NET libraries.

I’ll add more to this article at a later date but, for now, I’m using it to publish a series of 10+ .NET C# examples of how to use the Nethereum libraries to perform the most common task against the Ethereum blockchain platform.

The list of most common tasks includes the following:

  1. Get Protocol Version
  2. Get Max Block Number
  3. Get Account Balance
  4. Send Ether
  5. Wait for Transaction Receipt
  6. Scan Blocks in Blockchain
  7. List Personal Accounts (and their Balances)
  8. Scan Transactions in Blockchain
  9. Interact with an Existing (Deployed) Contract
  10. Interact with an Existing (Deployed) Contract with Events
  11. Get All Event Changes
  12. Get Contract Values History

Here is the primary C# file:

  • TextExamples.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using Nethereum.Hex.HexTypes;
using Nethereum.Web3;

namespace MWH.MyNethereum.QuickRef
{
 static public class TaskExamples
 {
 const int UNLOCK_TIMEOUT = 2 * 60; // 2 minutes (arbitrary)
 const int SLEEP_TIME = 5 * 1000; // 5 seconds (arbitrary)
 const int MAX_TIMEOUT = 2 * 60 * 1000; // 2 minutes (arbirtrary)

// These static public variables do not represent a recommended pattern
 static public string LastProtocolVersion = "";
 static public string LastTxHash = "";
 static public Nethereum.RPC.Eth.DTOs.TransactionReceipt LastTxReceipt = null;
 static public HexBigInteger LastMaxBlockNumber = new HexBigInteger(0);

static public async Task GetProtocolVersionExample(Web3 web3)
 {
 Console.WriteLine("GetProtocolVersionExample:");

var protocolVersion = await web3.Eth.ProtocolVersion.SendRequestAsync();
 Console.WriteLine("protocolVersion:\t" + protocolVersion.ToString());
 LastProtocolVersion = protocolVersion;
 }

static public async Task GetMaxBlockExample(Web3 web3)
 {
 Console.WriteLine("GetMaxBlockExample:");

var maxBlockNumber = await web3.Eth.Blocks.GetBlockNumber.SendRequestAsync();
 Console.WriteLine("maxBlockNumber:\t" + maxBlockNumber.Value.ToString());
 LastMaxBlockNumber = maxBlockNumber;
 }

static public async Task ScanBlocksExample(Web3 web3, ulong startBlockNumber, ulong endBlockNumber)
 {
 Console.WriteLine("ScanBlocksExample:");

long txTotalCount = 0;
 for (ulong blockNumber = startBlockNumber; blockNumber <= endBlockNumber; blockNumber++)
 {
 var blockParameter = new Nethereum.RPC.Eth.DTOs.BlockParameter(blockNumber);
 var block = await web3.Eth.Blocks.GetBlockWithTransactionsByNumber.SendRequestAsync(blockParameter);
 var trans = block.Transactions;
 int txCount = trans.Length;
 txTotalCount += txCount;
 if (blockNumber % 1000 == 0) Console.Write(".");
 if (blockNumber % 10000 == 0)
 {
 DateTime blockDateTime = Helpers.UnixTimeStampToDateTime((double)block.Timestamp.Value);
 Console.WriteLine(blockNumber.ToString() + " " + txTotalCount.ToString() + " " + blockDateTime.ToString());
 }
 }
 Console.WriteLine();
 }

static public async Task ScanTxExample(Web3 web3, ulong startBlockNumber, ulong endBlockNumber)
 {
 Console.WriteLine("ScanTxExample:");

long txTotalCount = 0;
 for (ulong blockNumber = startBlockNumber; blockNumber <= endBlockNumber; blockNumber++)
 {
 var blockParameter = new Nethereum.RPC.Eth.DTOs.BlockParameter(blockNumber);
 var block = await web3.Eth.Blocks.GetBlockWithTransactionsByNumber.SendRequestAsync(blockParameter);
 var trans = block.Transactions;
 int txCount = trans.Length;
 txTotalCount += txCount;
 foreach (var tx in trans)
 {
 try
 {
 var bn = tx.BlockNumber.Value;
 var th = tx.TransactionHash;
 var ti = tx.TransactionIndex.Value;

var rpt = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(th);
 var status = rpt.Status.Value;

var nc = tx.Nonce.Value;
 var from = tx.From;

Console.WriteLine(th.ToString() + " " + ti.ToString() + " " + from.ToString() + " " + status.ToString());

var to = tx.To;
 if (to == null) to = "to:NULL";
 var v = tx.Value.Value;
 var g = tx.Gas.Value;
 var gp = tx.GasPrice.Value;
 Console.WriteLine(th.ToString() + " " + ti.ToString() + " " + nc.ToString() + " " + from.ToString() + " " + to.ToString() + " " + v.ToString() + " " + g.ToString() + " " + gp.ToString());
 }
 catch (Exception ex)
 {
 Console.WriteLine("ScanTxExample.Tx:\t" + ex.ToString());
 if (ex.InnerException != null) Console.WriteLine("ScanTxExample.Tx:\t" + ex.InnerException.ToString());
 }
 }
 Console.WriteLine();
 }
 }

static public async Task GetAccountBalanceExample(Web3 web3, string accountAddress)
 {
 Console.WriteLine("GetAccountBalanceExample:");

var balanceWei = await web3.Eth.GetBalance.SendRequestAsync(accountAddress);
 var balanceEther = Web3.Convert.FromWei(balanceWei.Value);
 Console.WriteLine("accountAddress:\t" + accountAddress.ToString());
 Console.WriteLine("balanceEther:\t" + balanceEther.ToString());
 }

static public async Task ListPersonalAccountsExample(Web3 web3)
 {
 Console.WriteLine("ListPersonalAccountsExample:");

var accounts = await web3.Personal.ListAccounts.SendRequestAsync();
 foreach (var account in accounts)
 {
 var balanceWei = await web3.Eth.GetBalance.SendRequestAsync(account);
 var balanceEther = Web3.Convert.FromWei(balanceWei.Value);
 Console.WriteLine("account:\t" + account + " balanceEther:\t" + balanceEther.ToString());
 }
 }

static public async Task SendEtherExample(Web3 web3, string fromAddress, string fromPassword, string toAddress, long amountWei)
 {
 Console.WriteLine("SendEtherExample:");

var unlockResult = await web3.Personal.UnlockAccount.SendRequestAsync(fromAddress, fromPassword, UNLOCK_TIMEOUT);
 var sendTxHash = await web3.Eth.TransactionManager.SendTransactionAsync(fromAddress, toAddress, new HexBigInteger(amountWei));
 Console.WriteLine("fromAddress:\t" + fromAddress.ToString());
 Console.WriteLine("toAddress:\t" + toAddress.ToString());
 Console.WriteLine("amountWei:\t" + amountWei.ToString());
 Console.WriteLine("sendTxHash:\t" + sendTxHash.ToString());
 LastTxHash = sendTxHash;
 }

static public async Task WaitForTxReceiptExample(Web3 web3, string txHash)
 {
 Console.WriteLine("WaitForTxReceiptExample:");

int timeoutCount = 0;
 var txReceipt = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(txHash);
 while (txReceipt == null && timeoutCount < MAX_TIMEOUT)
 {
 Console.WriteLine("Sleeping...");
 Thread.Sleep(SLEEP_TIME);
 txReceipt = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(txHash);
 timeoutCount += SLEEP_TIME;
 }
 Console.WriteLine("timeoutCount " + timeoutCount.ToString());
 LastTxReceipt = txReceipt;
 }

static public async Task InteractWithExistingContractExample(Web3 web3, string fromAddress, string fromPassword, string contractAddress, string contractAbi)
 {
 Console.WriteLine("InteractWithExistingContractExample:");

var contract = web3.Eth.GetContract(contractAbi, contractAddress);

var setMessageFunction = contract.GetFunction("setMsg");
 var getMessageFunction = contract.GetFunction("getMsg");

string nowTimestamp = DateTime.UtcNow.ToString() + " UTC";
 Console.WriteLine("now:\t" + nowTimestamp);

var unlockResult = await web3.Personal.UnlockAccount.SendRequestAsync(fromAddress, fromPassword, UNLOCK_TIMEOUT);
 var txHash1 = await setMessageFunction.SendTransactionAsync(fromAddress, new HexBigInteger(900000), null, 1, "Hello World");
 Console.WriteLine("txHash1:\t" + txHash1.ToString());
 var txHash2 = await setMessageFunction.SendTransactionAsync(fromAddress, new HexBigInteger(900000), null, 2, nowTimestamp);
 Console.WriteLine("txHash2:\t" + txHash2.ToString());

var txReceipt2 = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(txHash2);
 int timeoutCount = 0;
 while (txReceipt2 == null && timeoutCount < MAX_TIMEOUT)
 {
 Console.WriteLine("Sleeping...");
 Thread.Sleep(SLEEP_TIME);
 txReceipt2 = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(txHash2);
 timeoutCount += SLEEP_TIME;
 }
 Console.WriteLine("timeoutCount:\t" + timeoutCount.ToString());

var txReceipt3 = await setMessageFunction.SendTransactionAndWaitForReceiptAsync(fromAddress, new HexBigInteger(900000), null, null, 2, nowTimestamp + " Wait");
 Console.WriteLine("txReceipt3:\t" + txReceipt3.TransactionHash.ToString());
 Console.WriteLine("txReceipt3:\t" + txReceipt3.CumulativeGasUsed.Value.ToString());

var getResult1 = await getMessageFunction.CallAsync<string>(1);
 Console.WriteLine("getResult1:\t" + getResult1.ToString());
 var getResult2 = await getMessageFunction.CallAsync<string>(2);
 Console.WriteLine("getResult2:\t" + getResult2.ToString());
 }

static public async Task InteractWithExistingContractWithEventsExample(Web3 web3, string fromAddress, string fromPassword, string contractAddress, string contractAbi)
 {
 Console.WriteLine("InteractWithExistingContractWithEventsExample:");

var contract = web3.Eth.GetContract(contractAbi, contractAddress);

var setMessageFunction = contract.GetFunction("setMsg");
 var getMessageFunction = contract.GetFunction("getMsg");
 var multipliedEvent = contract.GetEvent("MultipliedEvent");
 var newMessageEvent = contract.GetEvent("NewMessageEvent");

var filterAllMultipliedEvent = await multipliedEvent.CreateFilterAsync();
 var filterAllNewMessageEvent = await newMessageEvent.CreateFilterAsync();

string nowTimestamp = DateTime.UtcNow.ToString() + " UTC";
 Console.WriteLine("now:\t" + nowTimestamp);

var unlockResult = await web3.Personal.UnlockAccount.SendRequestAsync(fromAddress, fromPassword, UNLOCK_TIMEOUT);
 var txHash1 = await setMessageFunction.SendTransactionAsync(fromAddress, new HexBigInteger(900000), null, 1, "Hello World");
 Console.WriteLine("txHash1:\t" + txHash1.ToString());
 var txHash2 = await setMessageFunction.SendTransactionAsync(fromAddress, new HexBigInteger(900000), null, 2, nowTimestamp);
 Console.WriteLine("txHash2:\t" + txHash2.ToString());

var txReceipt2 = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(txHash2);
 int timeoutCount = 0;
 while (txReceipt2 == null && timeoutCount < MAX_TIMEOUT)
 {
 Console.WriteLine("Sleeping...");
 Thread.Sleep(SLEEP_TIME);
 txReceipt2 = await web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(txHash2);
 timeoutCount += SLEEP_TIME;
 }
 Console.WriteLine("timeoutCount:\t" + timeoutCount.ToString());

var txReceipt3 = await setMessageFunction.SendTransactionAndWaitForReceiptAsync(fromAddress, new HexBigInteger(900000), null, null, 2, nowTimestamp + " Wait");
 Console.WriteLine("txReceipt3:\t" + txReceipt3.TransactionHash.ToString());
 Console.WriteLine("txReceipt3:\t" + txReceipt3.CumulativeGasUsed.Value.ToString());

var getResult1 = await getMessageFunction.CallAsync<string>(1);
 Console.WriteLine("getResult1:\t" + getResult1.ToString());
 var getResult2 = await getMessageFunction.CallAsync<string>(2);
 Console.WriteLine("getResult2:\t" + getResult2.ToString());

var logMultipliedEvents = await multipliedEvent.GetFilterChanges<FunctionOutputHelpers.MultipliedEventArgs>(filterAllMultipliedEvent);
 foreach (var mea in logMultipliedEvents)
 {
 Console.WriteLine("multipliedEvent:\t" +
 mea.Event.sender + " " + mea.Event.oldProduct.ToString() + " " + mea.Event.value.ToString() + " " + mea.Event.newProduct.ToString());
 }

var logNewMessageEvents = await newMessageEvent.GetFilterChanges<FunctionOutputHelpers.NewMessageEventArgs>(filterAllNewMessageEvent);
 foreach (var mea in logNewMessageEvents)
 {
 Console.WriteLine("newMessageEvent:\t" +
 mea.Event.sender + " " + mea.Event.ind.ToString() + " " + mea.Event.msg.ToString());
 }
 }

static public async Task GetAllChangesExample(Web3 web3, string fromAddress, string fromPassword, string contractAddress, string contractAbi)
 {
 Console.WriteLine("GetAllChangesExample:");

var contract = web3.Eth.GetContract(contractAbi, contractAddress);
 var newMessageEvent = contract.GetEvent("NewMessageEvent");
 var filterAllNewMessageEvent = await newMessageEvent.CreateFilterAsync(fromAddress);
 var logNewMessageEvents = await newMessageEvent.GetAllChanges<FunctionOutputHelpers.NewMessageEventArgs>(filterAllNewMessageEvent);
 foreach (var mea in logNewMessageEvents)
 {
 Console.WriteLine("newMessageEvent:\t" +
 mea.Event.sender + " " + mea.Event.ind.ToString() + " " + mea.Event.msg.ToString());
 }
 }

static public async Task GetContractValuesHistoryUniqueOffsetValueExample(Web3 web3, string contractAddress, HexBigInteger recentBlockNumber, ulong numberBlocks, int offset)
 {
 Console.WriteLine("GetContractValuesHistoryUniqueOffsetValueExample:");

string previousValue = "";
 for (ulong blockNumber = (ulong)recentBlockNumber.Value; blockNumber > (ulong)recentBlockNumber.Value - numberBlocks; blockNumber--)
 {
 var blockNumberParameter = new Nethereum.RPC.Eth.DTOs.BlockParameter(blockNumber);
 var valueAtOffset = await web3.Eth.GetStorageAt.SendRequestAsync(contractAddress, new HexBigInteger(offset), blockNumberParameter);
 if (valueAtOffset != previousValue)
 {
 var block = await web3.Eth.Blocks.GetBlockWithTransactionsByNumber.SendRequestAsync(blockNumberParameter);
 DateTime blockDateTime = Helpers.UnixTimeStampToDateTime((double)block.Timestamp.Value);
 Console.WriteLine("blockDateTime:\t" + blockDateTime.ToString());

for (int storageOffset = 0; storageOffset < offset+2; storageOffset++)
 {
 var valueAt = await web3.Eth.GetStorageAt.SendRequestAsync(contractAddress, new HexBigInteger(storageOffset), blockNumberParameter);
 Console.WriteLine("value:\t" + blockNumber.ToString() + " " + storageOffset.ToString() + " " + valueAt + " " + Helpers.ConvertHex(valueAt.Substring(2)));
 }
 previousValue = valueAtOffset;
 }
 }
 }
 }
}

Here are some supporting files:

  • FunctionOutputHelpers.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Nethereum.Web3;
using Nethereum.ABI.FunctionEncoding.Attributes;

namespace MWH.MyNethereum.QuickRef
{
 static public class FunctionOutputHelpers
 {
 // event MultipliedEvent(
 // address indexed sender,
 // int oldProduct,
 // int value,
 // int newProduct
 // );

[FunctionOutput]
 public class MultipliedEventArgs
 {
 [Parameter("address", "sender", 1, true)]
 public string sender { get; set; }

[Parameter("int", "oldProduct", 2, false)]
 public int oldProduct { get; set; }

[Parameter("int", "value", 3, false)]
 public int value { get; set; }

[Parameter("int", "newProduct", 4, false)]
 public int newProduct { get; set; }

}

//event NewMessageEvent(
 // address indexed sender,
 // uint256 indexed ind,
 // string msg
 //);

[FunctionOutput]
 public class NewMessageEventArgs
 {
 [Parameter("address", "sender", 1, true)]
 public string sender { get; set; }

[Parameter("uint256", "ind", 2, true)]
 public int ind { get; set; }

[Parameter("string", "msg", 3, false)]
 public string msg { get; set; }
 }
 }
}
  • Helpers.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MWH.MyNethereum.QuickRef
{
 static public class Helpers
 {
 public static string ConvertHex(String hexString)
 {
 try
 {
 string ascii = string.Empty;

for (int i = 0; i < hexString.Length; i += 2)
 {
 String hs = string.Empty;

hs = hexString.Substring(i, 2);
 uint decval = System.Convert.ToUInt32(hs, 16);
 char character = System.Convert.ToChar(decval);
 ascii += character;

}

return ascii;
 }
 catch (Exception ex) { Console.WriteLine(ex.Message); }

return string.Empty;
 }

public static DateTime UnixTimeStampToDateTime(double unixTimeStamp)
 {
 // Unix timestamp is seconds past epoch
 System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
 dtDateTime = dtDateTime.AddSeconds(unixTimeStamp); // .ToLocalTime();
 return dtDateTime;
 }

public static DateTime JavaTimeStampToDateTime(double javaTimeStamp)
 {
 // Java timestamp is milliseconds past epoch
 System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
 dtDateTime = dtDateTime.AddMilliseconds(javaTimeStamp); // .ToLocalTime();
 return dtDateTime;
 }
 }
}

Here’s the Solidity code that is used to implement the Ethereum contract used in these examples:

  • Test3.sol
pragma solidity 0.4.19;

contract Test3 {

int public _product;
string[5] _msgs;
 
event MultipliedEvent(
address indexed sender,
int oldProduct,
int value,
int newProduct
);
 
event NewMessageEvent(
address indexed sender,
uint256 indexed ind,
string msg
);

function Test3() public {
_product = 1;
}

function multiply(int value) public returns(int product) {
int old = _product;
_product = value * _product;
MultipliedEvent( msg.sender, old, value, _product );
return _product;
}
 
function getProduct() public constant returns(int product) {
return _product;
}

function setMsg(uint256 i, string m) public returns(uint256 mi) {
_msgs[i] = m;
NewMessageEvent( msg.sender, i, m);
return -i;
}

function getMsg(uint256 index) public constant returns(string m) {
return _msgs[index];
}
}

I realize that this is a fairly crude way to publish code examples.  Any suggestions for a better approach will be appreciated.

Best regards,
Michael Herman (Toronto)

1 Comment

Filed under .NET Development, blockchain, Ethereum, Nethereum