During smart contract development, a project sometimes requires connecting with other contracts in the network. However, private variables in Solidity are inaccessible to any other contract and can only be read by the contracts themselves. These data can, however, be accessed from outside the blockchain. Let us examine the process of obtaining private data from smart contracts.
Accessing Private Data in Smart Contracts
Storage Architecture
The Ethereum Virtual Machine, or EVM, uses slots on the blockchain to store smart contract data in a big array with a length of 2**256. Up to 32 bytes of data can be stored in each memory slot. The state variables of smart contracts are stored by the EVM in the sequence in which they were declared in blockchain slots.
Space efficiency is the main goal of smart contract storage. Variables are packed into one 32-byte slot if two or more can fit into it, starting from the right.
uint8 => 1 byte
uint16 => 2 bytes and so on
uint256 => 32 bytes
bool => 1 byte
address => 20 byte
bytes1 => 1 byte
bytes2 => 2 bytes
Pre-requisites
First, Make sure that node js is installed in your system to check if Node.js is installed or not run “node -v” if it shows some version example-”v18.16.0". It means that nodejs is installed otherwise you can install nodejs from (https://nodejs.org/en) based on your OS.
Hardhat must be installed. We are using Hardhat for testing and deploying our smart contract.
For the test case, we use the Chai library.
Steps to Accessing Private Data
We can take the following actions to get private data from a Solidity smart contract. Here, we’ll be extracting data using ethers.js.
To begin with, we must read the contract and comprehend the declaration sequence of the state variables. Assume for a moment that we wish to use slot 0.
The memory slots of the contract on the blockchain can be read using ethers.js. Make use of the function below: await ethers.provider.getStorage(contract. target, slot);
This will return a result that is hex encoded, which we can easily decode using ether or a hex decoder of some like. parseInt(Number(slot0Bytes))
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
contract MyContract {
uint256 private privateData_0;
uint256 private privateData_1;
constructor(uint256 _privateData0,uint256 _privateData1){
privateData_0 = _privateData0;
privateData_1 = _privateData1;
}
}
Test script
const { ethers, upgrades } = require("hardhat");
const { BigNumber } = require('ethers')
const { expect } = require("chai");
describe('accessing private data', function(){
let deployer
let Contract
let addr1
let contract
beforeEach(async function(){
[deployer ,addr1,addr2] = await ethers.getSigners();
Contract = await ethers.getContractFactory('MyContract');
contract = await Contract.deploy(101,102);
const data = await contract.waitForDeployment();
console.log(
`deployed to ${Contract},${contract.target},${data}`
);
});
it('contract', async function(){ const private_1 = 101;
const private_2 = 102;
const slot = 0;
const slot1 = 1;
const slot0Bytes = await ethers.provider.getStorage(contract.target, slot);
const slot0Bytes1 = await ethers.provider.getStorage(contract.target, slot1);
const slotData = parseInt(Number(slot0Bytes))
const slotData_1 = parseInt(Number(slot0Bytes1))
expect(slotData).to.be.equals(parseInt(Number(private_1)));
expect(slotData_1).to.be.equals(parseInt(Number(private_2)));
})})
Run test script
- npx hardhat test
The test case that runs will confirm that the only integer read from slot 0 is 101, and the only integer read from slot 1 is 102. which both are private data.
Since we are working with public blockchains, private data in a smart contract is not private in the traditional sense. Blockchains cannot truly hide information from the outside world. We must use certain encryption algorithms if we wish to store sensitive data on-chain. For more about smart contract development, connect with our smart contract developers.