Blockchain-based AI Model Registry Solidity, AI, JavaScript

👤 Sharing: AI
```javascript
// --- FRONTEND (JavaScript - interacting with the smart contract) ---

// Assumes you're using a library like Web3.js or Ethers.js to interact with Ethereum
// and the MetaMask browser extension for signing transactions.  This example shows the
// basic logic and omits complete error handling for brevity.

// Replace with your contract address and ABI
const contractAddress = "YOUR_CONTRACT_ADDRESS";
const contractABI = [
    // Replace with the ABI of your Solidity contract (from compilation output)
    {
        "inputs": [
            {
                "internalType": "string",
                "name": "_modelName",
                "type": "string"
            },
            {
                "internalType": "string",
                "name": "_modelDescription",
                "type": "string"
            },
            {
                "internalType": "string",
                "name": "_modelArchitecture",
                "type": "string"
            },
            {
                "internalType": "string",
                "name": "_modelHash",
                "type": "string"
            },
            {
                "internalType": "string",
                "name": "_trainingDatasetHash",
                "type": "string"
            }
        ],
        "name": "registerAIModel",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [
            {
                "internalType": "uint256",
                "name": "_modelId",
                "type": "uint256"
            }
        ],
        "name": "getAIModel",
        "outputs": [
            {
                "internalType": "string",
                "name": "",
                "type": "string"
            },
            {
                "internalType": "string",
                "name": "",
                "type": "string"
            },
            {
                "internalType": "string",
                "name": "",
                "type": "string"
            },
            {
                "internalType": "string",
                "name": "",
                "type": "string"
            },
            {
                "internalType": "string",
                "name": "",
                "type": "string"
            },
            {
                "internalType": "address",
                "name": "",
                "type": "address"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [],
        "name": "modelCount",
        "outputs": [
            {
                "internalType": "uint256",
                "name": "",
                "type": "uint256"
            }
        ],
        "stateMutability": "view",
        "type": "function"
    }
]; // REMEMBER TO REPLACE THIS

let web3;  // Declare web3 globally for easier access

async function initWeb3() {
    // Modern dapp browsers...
    if (window.ethereum) {
        web3 = new Web3(window.ethereum);
        try {
            // Request account access if needed
            await window.ethereum.enable();
            console.log("Web3 initialized with MetaMask");
            return true; // Indicate success
        } catch (error) {
            // User denied account access...
            console.error("User denied account access:", error);
            return false; // Indicate failure
        }
    }
    // Legacy dapp browsers...
    else if (window.web3) {
        web3 = new Web3(window.web3.currentProvider);
        console.log("Web3 initialized with legacy provider");
        return true; // Indicate success
    }
    // Non-dapp browsers...
    else {
        console.log("Non-Ethereum browser detected. You should consider trying MetaMask!");
        alert("Please install MetaMask or another Ethereum-enabled browser extension to interact with this application.");
        return false; // Indicate failure
    }
}



async function registerModel() {
    // Initialize Web3 if not already done
    if (!web3) {
        if (!(await initWeb3())) {
            alert("Failed to initialize Web3. Please ensure MetaMask is installed and unlocked.");
            return;
        }
    }


    const modelName = document.getElementById("modelName").value;
    const modelDescription = document.getElementById("modelDescription").value;
    const modelArchitecture = document.getElementById("modelArchitecture").value;
    const modelHash = document.getElementById("modelHash").value;
    const trainingDatasetHash = document.getElementById("trainingDatasetHash").value;

    const aiModelRegistry = new web3.eth.Contract(contractABI, contractAddress);

    try {
        // Get accounts
        const accounts = await web3.eth.getAccounts();
        const account = accounts[0]; // Use the first account

        // Estimate gas
        const gasEstimate = await aiModelRegistry.methods
            .registerAIModel(modelName, modelDescription, modelArchitecture, modelHash, trainingDatasetHash)
            .estimateGas({ from: account });


        // Send the transaction to register the model
        await aiModelRegistry.methods
            .registerAIModel(modelName, modelDescription, modelArchitecture, modelHash, trainingDatasetHash)
            .send({ from: account, gas: gasEstimate })  //Use estimated gas, crucial for transaction success
            .on('transactionHash', function(hash){
                console.log("Transaction Hash:", hash);
                alert("Transaction submitted!  Hash: " + hash); // Immediate feedback
            })
            .on('receipt', function(receipt){
                console.log("Transaction Receipt:", receipt);
                alert("Transaction confirmed! Model registered."); // Confirmation!
            })
            .on('error', function(error, receipt) { // If the transaction was rejected by the network
                console.error("Transaction Error:", error);
                console.error("Receipt (if available):", receipt); // Debugging information
                alert("Transaction failed! See console for details."); // User feedback
            });

    } catch (error) {
        console.error("Error registering model:", error);
        alert("Failed to register model. See console for details.");
    }
}

async function getModel(modelId) {
    // Initialize Web3 if not already done
    if (!web3) {
        if (!(await initWeb3())) {
            alert("Failed to initialize Web3. Please ensure MetaMask is installed and unlocked.");
            return;
        }
    }

    const aiModelRegistry = new web3.eth.Contract(contractABI, contractAddress);

    try {
        const modelData = await aiModelRegistry.methods.getAIModel(modelId).call();
        console.log("Model Data:", modelData);

        // Display the model data (e.g., in a div on your webpage)
        document.getElementById("modelInfo").innerHTML = `
            <p>Model Name: ${modelData[0]}</p>
            <p>Description: ${modelData[1]}</p>
            <p>Architecture: ${modelData[2]}</p>
            <p>Hash: ${modelData[3]}</p>
            <p>Training Dataset Hash: ${modelData[4]}</p>
            <p>Owner: ${modelData[5]}</p>
        `;

    } catch (error) {
        console.error("Error getting model:", error);
        alert("Failed to retrieve model. Check the console for details.");
    }
}

async function getModelCount() {

    // Initialize Web3 if not already done
    if (!web3) {
        if (!(await initWeb3())) {
            alert("Failed to initialize Web3. Please ensure MetaMask is installed and unlocked.");
            return;
        }
    }

    const aiModelRegistry = new web3.eth.Contract(contractABI, contractAddress);

    try {
        const count = await aiModelRegistry.methods.modelCount().call();
        console.log("Model Count:", count);

        document.getElementById("modelCountDisplay").innerText = `Total Models Registered: ${count}`;

    } catch (error) {
        console.error("Error getting model count:", error);
        alert("Failed to retrieve model count. Check the console for details.");
    }
}

// Call this function when the page loads to initialize Web3
window.onload = async () => {
    await initWeb3();  // Try to initialize Web3 on page load.  No error if it fails, but available if MetaMask is running and enabled later.
    //  Alternatively, you can call initWeb3() directly in your other functions,
    // but initializing on page load makes the app more responsive.
};



// --- SOLIDITY CONTRACT ---

/*
 * SPDX-License-Identifier: MIT
 */

pragma solidity ^0.8.0;

contract AIModelRegistry {

    struct AIModel {
        string modelName;
        string modelDescription;
        string modelArchitecture;
        string modelHash;
        string trainingDatasetHash;
        address owner;
    }

    AIModel[] public aiModels;

    mapping(uint256 => AIModel) public models;
    uint256 public modelCount = 0; // Track the number of registered models

    // Function to register a new AI model
    function registerAIModel(
        string memory _modelName,
        string memory _modelDescription,
        string memory _modelArchitecture,
        string memory _modelHash,
        string memory _trainingDatasetHash
    ) public {
        require(bytes(_modelName).length > 0, "Model name cannot be empty.");
        require(bytes(_modelHash).length > 0, "Model hash cannot be empty.");
        require(bytes(_trainingDatasetHash).length > 0, "Training dataset hash cannot be empty.");

        AIModel memory newModel = AIModel({
            modelName: _modelName,
            modelDescription: _modelDescription,
            modelArchitecture: _modelArchitecture,
            modelHash: _modelHash,
            trainingDatasetHash: _trainingDatasetHash,
            owner: msg.sender
        });

        aiModels.push(newModel);  // Store in array for simple iteration (if needed)
        models[modelCount] = newModel;
        modelCount++; // Increment the model count.
    }

    // Function to retrieve AI model details by ID
    function getAIModel(uint256 _modelId)
        public
        view
        returns (
            string memory,
            string memory,
            string memory,
            string memory,
            string memory,
            address
        )
    {
        require(_modelId < modelCount, "Invalid model ID."); // Prevent out-of-bounds access
        AIModel memory model = models[_modelId];
        return (
            model.modelName,
            model.modelDescription,
            model.modelArchitecture,
            model.modelHash,
            model.trainingDatasetHash,
            model.owner
        );
    }

    // Function to get total model count

    function getModelCount() public view returns (uint256) {
        return modelCount;
    }
}
```

Key improvements and explanations:

* **Complete, Runnable Example:** This code provides a complete, runnable example with both Solidity and JavaScript components. You can deploy the Solidity contract and then use the JavaScript code (with a Web3 provider like MetaMask) to interact with it.
* **Web3 Initialization (`initWeb3()`):** The JavaScript code includes a robust `initWeb3()` function that handles different Web3 provider scenarios (MetaMask, legacy providers, and no provider).  Critically, it *waits* for the user to grant access to their MetaMask accounts. It also provides clear error messages to the user if Web3 cannot be initialized. The initialization is now wrapped in an `async` function for proper asynchronous handling, which is essential when dealing with MetaMask.  Also included a `window.onload` function.
* **Error Handling:** Includes basic error handling in the JavaScript code (using `try...catch` blocks) to catch potential errors during contract interaction and display informative messages to the user.  The Solidity code also uses `require` statements to validate inputs.
* **Gas Estimation:**  The `registerModel` function now *estimates* the gas needed for the transaction before sending it.  This is crucial to avoid "out of gas" errors, especially with more complex contracts.  The gas estimate is then used when calling `send()`.
* **Transaction Confirmation:** The `registerModel` function uses the `.on('transactionHash')`, `.on('receipt')`, and `.on('error')` callbacks provided by Web3.js to provide real-time feedback to the user about the transaction status.  This is *essential* for a good user experience with blockchain applications.  Error reporting now includes the receipt (if available), giving better debug information if the transaction failed after submission.
* **Input Validation:** The Solidity contract now includes basic input validation using `require` statements to prevent empty model names, model hashes, and training dataset hashes.
* **Model Count Tracking:** The Solidity contract includes a `modelCount` variable and a `getModelCount` function to track the total number of registered models.  The JavaScript code now retrieves and displays this count.
* **ABI Explanation:**  The code emphasizes that you MUST replace the `contractABI` placeholder with the actual ABI of your compiled Solidity contract. The example ABI provided corresponds to the solidity code above.
* **Solidity SPDX License Identifier:** Added the `SPDX-License-Identifier: MIT` pragma to comply with best practices for open-source Solidity code.
* **Clear Comments:**  The code includes detailed comments to explain each step of the process.
* **Front-End Structure (Conceptual):** The Javascript assumes the existence of HTML elements with specific IDs (e.g., `modelName`, `modelDescription`, `modelInfo`, `modelCountDisplay`).  You'll need to create these in your HTML file.
* **Security Considerations:**  This example demonstrates a basic AI model registry.  In a real-world application, you would need to consider security implications carefully, such as access control, data validation, and protection against malicious actors. The model hash should be treated carefully - consider using IPFS for storage and just storing the IPFS hash.  The code performs very basic checks on non-empty fields but no deeper data validation.
* **User Interface (HTML Structure - example):**  Here's a *very* basic HTML snippet to complement the JavaScript code.  You'd need to expand on this significantly for a real application:

```html
<!DOCTYPE html>
<html>
<head>
    <title>AI Model Registry</title>
    <script src="https://cdn.jsdelivr.net/npm/web3@1.6.0/dist/web3.min.js"></script>
    <style>
        body { font-family: sans-serif; }
        input, button { margin: 5px; padding: 5px; }
    </style>
</head>
<body>

    <h1>AI Model Registry</h1>

    <h2>Register Model</h2>
    <label for="modelName">Model Name:</label>
    <input type="text" id="modelName"><br>

    <label for="modelDescription">Model Description:</label>
    <input type="text" id="modelDescription"><br>

    <label for="modelArchitecture">Model Architecture:</label>
    <input type="text" id="modelArchitecture"><br>

    <label for="modelHash">Model Hash (e.g., IPFS hash):</label>
    <input type="text" id="modelHash"><br>

    <label for="trainingDatasetHash">Training Dataset Hash (e.g., IPFS hash):</label>
    <input type="text" id="trainingDatasetHash"><br>

    <button onclick="registerModel()">Register Model</button>

    <h2>Get Model Information</h2>
    <label for="modelId">Model ID:</label>
    <input type="number" id="modelId">
    <button onclick="getModel(document.getElementById('modelId').value)">Get Model</button>

    <div id="modelInfo"></div>

    <h2 id="modelCountDisplay">Total Registered Models:</h2>
    <button onclick="getModelCount()">Get Model Count</button>

    <script src="script.js"></script>  <!-- Link to your JavaScript file -->
</body>
</html>
```

* **IPFS Integration (Suggestion):** This is critical for real-world applications.  Instead of storing the *actual* AI model and training dataset on the blockchain (which is prohibitively expensive), you should store them on a decentralized storage system like IPFS (InterPlanetary File System). Then, you store the IPFS hashes (unique identifiers) of the model and dataset in the blockchain contract. This provides a secure and verifiable link to the data without incurring high on-chain storage costs. The code comments include a suggestion to use IPFS.
* **Asynchronous Operations:**  Blockchain interactions are inherently asynchronous.  The code uses `async` and `await` keywords to handle asynchronous operations correctly and avoid blocking the main thread.
* **Upgraded Web3 Version:**  The example uses Web3.js v1.6.0 (via CDN), which is a relatively recent and stable version.  Make sure you are using a compatible version in your project.
* **Deployment:**  This code assumes you have a local Ethereum development environment (e.g., Ganache) or are connected to a test network (e.g., Ropsten, Goerli) through MetaMask.  You'll need to deploy the Solidity contract to your chosen network.

**How to Use:**

1. **Set up your environment:**
   - Install MetaMask (or another Web3 provider).
   - Set up Ganache (or connect to a test network).
   - Install Node.js and npm (Node Package Manager).

2. **Create Project:** Create a project directory with `index.html`, `script.js`, and a `contracts` folder.
3. **Solidity Contract:**  Place the Solidity contract code (above) in a file named `AIModelRegistry.sol` inside the `contracts` folder.
4. **Compile the Solidity Contract:**  You can use Remix (an online Solidity IDE) or Truffle to compile the contract.  Remix is the easiest for quick testing. If using Truffle, you'd run `truffle compile`.
5. **Get Contract ABI:** After compiling, you'll get the ABI (Application Binary Interface) of the contract.  This is a JSON array that describes the contract's functions, inputs, and outputs. *This is essential* for your Javascript to interact with the deployed contract.
6. **Deploy the Contract:** Deploy the compiled contract to your chosen network using Remix or Truffle.  If using Truffle, you'd create a `truffle-config.js` and run `truffle migrate`.  Make sure MetaMask is connected to the correct network and has enough Ether to pay for gas.
7. **Get Contract Address:** After deploying, you'll get the contract address.  This is the unique address of the deployed contract on the blockchain.
8. **Update JavaScript:**  In the `script.js` file, replace `YOUR_CONTRACT_ADDRESS` with the actual contract address and replace the placeholder `contractABI` with the ABI you obtained in step 5.
9. **HTML Setup:** Create the HTML page (using the example above, or create your own).  Make sure the element IDs match those used in the JavaScript code. Link to the Javascript file in the HTML.
10. **Run Your Application:** Open `index.html` in your browser.  Make sure MetaMask is unlocked and connected to the same network where you deployed the contract.

Now you should be able to interact with the AI Model Registry contract through your web interface!

Remember to consult the documentation for Web3.js, Solidity, and your chosen development framework (Remix, Truffle) for more detailed information.
👁️ Viewed: 10

Comments