Solidity - a mapping based on the hash of a string value - solidity

I am trying to create mapping of type mapping(string => string) where the you store some text by keyed by its the string representation of its hash, but I've been stymied by the inability to take the calculated hash value and convert it to its string representation.
I tried the below, but it doesn't work. The hashing function appears to work, but the conversion to string doesn't. (Running function hash() returns an error which I don't really understand.
pragma solidity 0.8.4;
contract HashTextMap {
mapping(string=>string) textMap;
function set(string memory text) public {
bytes32 val;
val = sha256(abi.encodePacked(text));
string memory key = string(abi.encodePacked(val));
textMap[key] = text;
}
function get(string memory key) public view returns(string memory) {
return textMap[key];
}
function hash(string memory text) public pure returns(string memory) {
bytes32 val;
val = sha256(abi.encodePacked(text));
string memory key = string(abi.encodePacked(val));
return key;
}
}
Running this in the remix ide, the contract compiles and sets returns normally, but attempting I can't text get because I can't get the hash using hash() which produces this error.
{ "error": "Failed to decode output: null: invalid codepoint at offset 0; unexpected continuation byte (argument=\"bytes\", value={\"0\":153,\"1\":168,\"2\":124,\"3\":145,\"4\":53,\"5\":23,\"6\":70,\"7\":37,\"8\":43,\"9\":238,\"10\":126,\"11\":38,\"12\":250,\"13\":191,\"14\":48,\"15\":2,\"16\":61,\"17\":234,\"18\":227,\"19\":36,\"20\":138,\"21\":6,\"22\":125,\"23\":166,\"24\":226,\"25\":63,\"26\":146,\"27\":129,\"28\":199,\"29\":135,\"30\":194,\"31\":139}, code=INVALID_ARGUMENT, version=strings/5.4.0)" }

This should help you
Solidity: How to represent bytes32 as string
The problem is that currently you are trying to convert your hash to a utf-8 string. The hash has values that aren't supported by utf-8. I think what you meant to do, was represent your hash as a string.

Related

Solidity: I need to reference bytes constants efficiently

I am implementing an on-chain font in Solidity. It works great, but I am not able to eliminate unnessary copies of bytes from code space (bytes constants) to the storage.
Here is the current implementation.
contract LondrinaSolid is IFontProvider {
uint constant fixed_height = 1024;
uint constant fixed_baseline = 805;
bytes constant font_0 = "\x4d\x60\xd1\x74\x05\x43\x8a\x56\x1f\x29\x56\x0b\xd2\x55\x21\x63\x50\x00\x00\x45\x62\x2e\x45\x4a\xc5\x45\xf4\x19\x45\xf5\x4b\x45\xf3\xb0\x45\xff\x65\x45\xfe\xeb\x55\x39\x2e\x56\x3b\x44\x55\x8b\x73\x65\x0c\x4c\x05\x73\xc0\x45\x02\xc5\x35\x97\x63\x50\x05\x95\x44\xfe\x21\x44\xb7\xcd\x03\x5a\x6d\x40\x75\x54\x06\x63\xfc\x54\x83\xe6\x54\x99\xc7\x54\x9a\xe0\x54\x01\xe3\x44\xf5\xd2\x44\xc9\xef\x44\xd5\xef\x44\x66\xef\x44\x66\x0b\x45\x72\x0b\x45\x3e\x40\x45\x40\x73\x50\x3d\x73\x55\x39\xf7\x05\x5a";
bytes constant font_1 = "\x4d\x50\xbc\x27\x06\x73\xf7\x54\xf4\xf5\x64\x27\xfe\x54\xc6\xfe\x54\xc6\x63\x50\x00\x00\x55\x4e\x0d\x55\x7c\x0c\x05\x73\x4e\x45\xfb\x4f\x45\xea\x05\x35\x8a\x08\x35\x61\x04\x35\xbd\xfe\x34\xaf\x63\x50\x00\x00\x45\xa1\xfa\x44\x7e\xfb\x04\x73\x9d\x54\x02\x99\x54\x01\x63\x50\x00\x00\x45\xbd\x64\x45\xac\x80\x05\x53\x09\x55\xfb\x0a\x65\x0d\x63\x50\x00\x00\x55\x1b\x14\x55\x4b\x1f\x05\x73\x46\x55\x0f\x4b\x55\x0f\x18\x45\xf9\x1c\x45\xed\x5a\x00";
bytes constant font_2 = "\x4d\x50\xd3\x57\x06\x73\x0a\x45\xa6\x18\x45\x93\x39\x45\xd6\x4b\x55\x0d\xfe\x54\x66\xcc\x54\x81\xb4\x54\x33\x7f\x54\x53\xb6\x54\x3b\xb2\x54\x41\xe8\x54\x24\xe3\x54\x4f\xf6\x54\xbb\xf5\x54\xc3\x63\x50\x00\x00\x55\x0f\x04\x55\x1e\x05\x05\x73\xbd\x45\xfb\xd4\x45\xfb\xee\x45\xfd\xf6\x45\xfd\x08\x45\xfa\x08\x45\xf7\xfd\x44\xb7\xff\x44\xab\xfd\x44\xcc\xf6\x44\xbc\x63\x50\x00\x00\x45\x04\x06\x35\xe9\x02\x55\x00\x00\x55\x23\xb5\x54\x48\x9f\x04\x73\x99\x45\xb4\xb9\x45\x90\x31\x45\xc5\x31\x45\x7f\xfc\x44\x56\xa4\x44\x14\xf2\x43\xe0\xc0\x53\x02\x53\x40\xf6\xbb\x55\x15\x58\x06\x63\x00\x55\x00\x39\x55\x15\xbe\x45\xff\x5a\x00";
...
bytes constant font_X = "\x4d\x50\x09\x35\x05\x73\x40\x55\x93\x4f\x55\xc7\x2f\x55\x94\x2e\x55\xad\xce\x54\xaa\xc8\x54\xbe\xcd\x54\xa5\xc9\x54\xad\x63\x50\x00\x00\x55\x28\x10\x55\x60\x0e\x05\x73\x50\x45\xfd\x50\x45\xfd\x63\x50\x00\x00\x55\x1e\xaf\x54\x25\x98\x04\x73\x1f\x45\x96\x1f\x45\x96\x63\x50\x00\x00\x55\x1c\x6a\x55\x20\x7a\x05\x73\x13\x55\x48\x19\x55\x51\x63\x50\x00\x00\x55\x30\x0e\x55\x5d\x09\x05\x73\x52\x55\x01\x57\x55\x02\x63\x50\x00\x00\x45\xe5\x9f\x44\xd8\x6e\x04\x73\xc5\x44\x3a\xc2\x44\x1d\x63\x50\x00\x00\x55\x34\x52\x54\x41\x29\x04\x73\x34\x45\x51\x34\x45\x51\x63\x50\x00\x00\x45\xb3\x01\x45\xa2\x01\x05\x73\xa1\x54\x03\x99\x54\x04\x63\x50\x00\x00\x45\xca\xc9\x45\xc5\xd0\x55\x00\x00\x45\xe3\xa5\x44\xe0\x93\x04\x73\xe8\x44\xa0\xe8\x44\xa0\x63\x50\x00\x00\x45\x76\xff\x44\x3b\x05\x05\x5a";
bytes constant font_Y = "\x4d\x50\x17\x30\x05\x73\x19\x55\x59\x30\x55\x8d\x57\x55\xdc\x57\x55\xe8\x63\x50\x00\x00\x45\xc5\x9e\x45\xbd\xb1\x05\x53\x12\x85\x1d\x10\x85\x22\x63\x50\x00\x00\x55\x42\x04\x55\x64\x03\x05\x73\x4a\x45\xfd\x58\x55\x01\x63\x50\x00\x00\x55\x3f\x56\x54\x55\x2e\x04\x53\xb6\x66\x15\xcb\x56\xe0\x73\x50\x39\x5f\x54\x3a\x51\x04\x63\x00\x55\x00\xb2\x44\xf2\x4c\x54\x07\x00\x55\x00\xbb\x54\xc7\xb9\x54\xcc\x00\x55\x00\xbe\x44\x48\xbc\x44\x34\x00\x55\x00\xeb\x44\xee\xab\x44\xf3\x73\x40\xc0\x08\x45\xa5\x07\x05\x5a";
bytes constant font_Z = "\x4d\x50\x0b\x33\x05\x73\x0a\x55\x33\x09\x55\x4f\x03\x55\x4b\x0d\x55\x54\x63\x50\x00\x00\x55\xeb\x06\x55\xfc\x0c\x55\x00\x00\x45\x8a\xa5\x45\x7a\xb9\x05\x53\x26\x75\x4a\x19\x75\x73\x63\x50\x00\x00\x55\x01\x44\x55\x01\x5c\x05\x73\x04\x55\x4e\x0c\x55\x58\x63\x50\x00\x00\x55\xab\xf8\x54\xcf\xf9\x04\x73\xdb\x55\x03\x06\x56\x07\x63\x50\x00\x00\x55\x0e\x6b\x54\x02\x46\x54\x00\x00\x45\x0c\xff\x34\xf6\x08\x55\x00\x00\x55\x92\x2d\x54\xa4\x14\x04\x73\x6a\x45\x64\x6d\x45\x59\x01\x45\xad\x02\x45\x9d\xff\x44\xb5\xfc\x44\xb0\x63\x50\x00\x00\x45\x35\xfd\x44\x12\xfc\x04\x73\x3f\x54\x01\xf7\x53\x09\x5a\x00";
mapping(uint => bytes) fontData;
mapping(uint => uint) widths;
constructor() {
registerAll();
}
function _register(string memory _char, bytes memory _bytecode, uint _width) internal {
uint key = uint(uint8(bytes(_char)[0]));
if (_bytecode.length > 0) {
fontData[key] = _bytecode;
}
widths[key] = _width;
}
function registerAll() external onlyOwner {
_register("0", font_0, 554);
_register("1", font_1, 414);
_register("2", font_2, 540);
...
_register("X", font_X, 531);
_register("Y", font_Y, 531);
_register("Z", font_Z, 531);
}
function height() external pure override returns(uint) {
return fixed_height;
}
function baseline() external pure override returns(uint) {
return fixed_baseline;
}
function widthOf(string memory _char) external view override returns(uint) {
uint key = uint(uint8(bytes(_char)[0]));
return widths[key];
}
function pathOf(string memory _char) external view override returns(bytes memory) {
uint key = uint(uint8(bytes(_char)[0]));
return fontData[key];
}
}
The problem is in the _register method, which stores the mapping between the charactor and the vector data in the "fontData". Even thought the font data itself is already in this smart contract, it copies it to the "memory" space when calling this method and copies it into the "storage", which is quite expensive (12M units of gas).
One possible work around is to eliminate the _register method, and implement a binary search in pathOf method to directly return font_X, but that code is ugly and not scalable.
Ideally, I just want to store the references to those font data in "fontData" and return them in pathOf method.
I'd appreciate any suggestions, including writing some assembly solution (which I am comfortable with).
I was able to solve this problem by creating a function for each font, and having a mapping from character codes to those functions in the storage.
With this change, I was able to reduce the deployment cost of one particular font from 0.13ETH to 0.027ETH (assuming 30gwei gas price).

testing solidity - Error: invalid BigNumber value, when passing object as argument

I have a function in my Solidity which takes a struct as first parameter:
function mintGenesisAnimal(AnimalInfo memory _animalInfo, string memory _tokenUri) onlyOwner public {
// ...
}
but when I'm trying to test this function with the code below:
const animalInfo = {
raceName: 'Tiger',
}
await Animal.mintGenesisAnimal(animalInfo, 'https://google.com')
The test fails with a weird issue relative to "BigNumber":
Error: invalid BigNumber value (argument="value", value=undefined, code=INVALID_ARGUMENT, version=bignumber/5.6.0)
Why is a BigNumber reported when I'm trying to pass a struct (js object) as parameter ?

Chainlink VRF : Error encoding arguments: Error: invalid BigNumber string

I'm trying to get a random number with Chainlink VRF,
So Hi have follow this demo step by step : https://www.youtube.com/watch?v=JqZWariqh5s
here is what i've copied on Remix :
pragma solidity 0.6.6;
import "https://raw.githubusercontent.com/smartcontractkit/chainlink/master/evm-contracts/src/v0.6/VRFConsumerBase.sol";
contract RandomNumberConsumer is VRFConsumerBase {
bytes32 public keyHash;
uint256 public fee;
uint256 public randomResult;
constructor() VRFConsumerBase(
0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9, // VRF Coordinator
0xa36085F69e2889c224210F603D836748e7dC0088 // LINK Token
) public
{
keyHash = 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4;
fee = 0.1 * 10 ** 18; // 0.1 LINK
}
function getRandomNumber(uint256 userProvidedSeed) public returns (bytes32 requestId) {
return requestRandomness(keyHash, fee, userProvidedSeed);
}
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
randomResult = randomness.mod(50).add(1);
}
}
when i click on getRandomNumber, i always get this error :
Error encoding arguments: Error: invalid BigNumber string (argument="value", value="", code=INVALID_ARGUMENT, version=bignumber/5.0.8)
and with the fulfillRandomness, i get this error :
Error encoding arguments: Error: invalid arrayify value (argument="value", value="", code=INVALID_ARGUMENT, version=bytes/5.0.5)
Add some seed number into the function, and then click it.
Also, be sure to fund it with LINK.
Also, fulfillRandomness is only callable by the Chainlink VRF, so no worries on that part.
It looks like you are not passing the userProvidedSeed as an argument to getRandomNumber()
Try putting any number into the box beside the getRandomNumber method in Remix and then click on the method.
Also, fulfillRandomness is only callable by the Chainlink VRF, so do no worry about calling that function.

Trying to make an array with a variable size in solidity

I am trying to write string to the blockchain using events. This will cost a lot of gas regularly, so I am attempting to compress my strings. They become compressed into a uint8array in js. Here is my solidity script:
pragma solidity ^0.4.18;
contract EthProj {
event Message(uint8[] message, address add, uint256 cost);
event Username(uint8[] name, address add, uint256 cost);
function setMessage(uint8[] _fMessage) public {
uint8[] memory output = new uint8[](_fMessage.length);
output = _fMessage;
emit Message(output, msg.sender, gasleft());
}
function setUsername(uint8[] _userName) public {
emit Username(_userName, msg.sender, gasleft());
}
}
My goal with this is to have the size of the array be dependent on the size of the compressed text, but I get invalid number of arguments error when calling it using this:
message = document.getElementById("MessageBox").value;
compressed = shoco.compress(message);
EthProj.setMessage.sendTransaction(compressed, {from: document.getElementById("add").value});`
Can you not make an array with variable size, and if I can't, than how do I go about achieving my goal? The error is: Invalid number of arguments to solidity function

eth.call on web3 interface returns null value for contract function returning array of bytes32/strings

I am trying to run a bidding smart contract on a private blockchain and my smart contract is working on the Remix IDE and the same works on my private chain except for one function [dataOwnedBy()] which is suposed to return an array of bytes32 but returns all zero values in geth console.
I have compiled and deployed my smart contract using truffle.
The function which is not working is : (along with data declaration snippet and other function prototypes)
struct data{
bytes32 data_id;
address bidder;
uint bid;
}
mapping(bytes32=>data) bidInfo;
mapping(address=>data[]) dataOwned; //data owned by each address
address[] dataOwners; //list of address who own data
function Bid(bytes32 data_id) public payable { ... }
function closeBid(bytes32 data_id) public { ... }
function whoOwns(bytes32 _data_id) constant public returns (address){ ... }
function dataOwnedBy(address _addr) constant public returns (bytes32[10]){
uint length = dataOwned[_addr].length;
bytes32[10] memory _idArray;
for (uint i=0;i<length;i++){
_idArray[i] = (dataOwned[_addr][i].data_id);
}
return _idArray;
}
After closing the bid, when I query the above function with the winner's address, it returns array of size 10 bytes32 values, all equal to zero, where it should be returning the data_ids owned by the address.!
Version Information from console
> web3.version.api
"0.20.1"
truffle(development)> version
Truffle v3.4.11 (core: 3.4.11)
Solidity v0.4.15 (solc-js)
This is the console output :
playbid.whoOwns("data_id1")
"0x7d8eb703bd863313325b784ac35017614484f2e7"
playbid.dataOwnedBy("0x7d8eb703bd863313325b784ac35017614484f2e7")
["0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000"]
Instead the first value of the array should be the hex of "data_id1".
Don't know what is going wrong here, but it works perfectly fine on Remix IDE.
Thanks in advance !
As your code is working OK in remix, there is no problem with the smart contract code. I experienced same issue when I wanted to return some arrays back to my web3j powered java app. I also tested web3js and encountered the same problem. The returned array was broken the same way.
I ended up in serializing and deserializing arrays to strings with a delimiter, both in inputs and outputs.