My solidity code example:
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.2;
library TestLibrary {
function sz_varint(uint256 i) internal pure returns (uint256) {
uint256 count = 1;
assembly {
i := shr(7, i)
for {} gt(i, 0) {} {
i := shr(7, i)
count := add(count, 1)
}
}
return count;
}
function encode_varint_assembly(uint256 x, uint256 p, bytes memory bs) internal pure returns (uint256) {
uint256 sz = 0;
assembly {
let bsptr := add(bs, p)
let byt := and(x, 0x7f)
for {} gt(shr(7, x), 0) {} {
mstore8(bsptr, or(0x80, byt))
bsptr := add(bsptr, 1)
sz := add(sz, 1)
x := shr(7, x)
byt := and(x, 0x7f)
}
mstore8(bsptr, byt)
sz := add(sz, 1)
}
return sz;
}
function encode_varint_assembly_nomstore8(uint256 x, uint256 p, bytes memory bs) internal pure returns (uint256) {
uint256 sz = 0;
assembly {
let bsptr := add(bs, p)
let byt := and(x, 0x7f)
for {} gt(shr(7, x), 0) {} {
//mstore8(bsptr, or(0x80, byt))
bsptr := add(bsptr, 1)
sz := add(sz, 1)
x := shr(7, x)
byt := and(x, 0x7f)
}
//mstore8(bsptr, byt)
sz := add(sz, 1)
}
return sz;
}
function encode_varint(uint256 x, uint256 p, bytes memory bs) internal pure returns (uint256) {
uint256 tmp = x;
uint256 idx = p;
bytes1 byt = bytes1(uint8(tmp & 0x7f));
while (tmp > 0x7f) {
bs[idx] = byt | 0x80;
tmp = tmp >> 7;
byt = bytes1(uint8(tmp & 0x7f));
idx += 1;
}
bs[idx] = byt;
return idx - p + 1;
}
}
contract TestContract {
function encode_varint_assembly(uint256 x) public pure returns(bytes memory) {
uint256 sz = TestLibrary.sz_varint(x);
bytes memory buffer = new bytes(sz);
TestLibrary.encode_varint_assembly(x, 0, buffer);
return buffer;
}
function encode_varint_assembly_nomstore8(uint256 x) public pure returns(bytes memory) {
uint256 sz = TestLibrary.sz_varint(x);
bytes memory buffer = new bytes(sz);
TestLibrary.encode_varint_assembly_nomstore8(x, 0, buffer);
return buffer;
}
function encode_varint(uint256 x) public pure returns(bytes memory) {
uint256 sz = TestLibrary.sz_varint(x);
bytes memory buffer = new bytes(sz);
TestLibrary.encode_varint(x, 0, buffer);
return buffer;
}
}
try running some unit tests in go using abigen
here it's my go code
package main
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
)
func main() {
auth, client := setup()
_, _, entry, err := DeployTestContract(auth, client)
if err != nil {
panic(err)
}
client.Commit()
res, err := entry.EncodeVarint(nil, big.NewInt(10))
if err != nil {
panic(err)
}
fmt.Println("EncodeVarint", res)
res, err = entry.EncodeVarintAssemblyNomstore8(nil, big.NewInt(10))
if err != nil {
panic(err)
}
fmt.Println("EncodeVarintAssemblyNomstore8", res)
res, err = entry.EncodeVarintAssembly(nil, big.NewInt(10))
if err != nil {
panic(err)
}
fmt.Println("EncodeVarintAssembly", res)
}
func setup() (*bind.TransactOpts, *backends.SimulatedBackend) {
gAlloc := make(map[common.Address]core.GenesisAccount, 1)
deployerKey, err := crypto.GenerateKey()
if err != nil {
panic(err)
}
deployerAuth := bind.NewKeyedTransactor(deployerKey)
gAlloc[deployerAuth.From] = core.GenesisAccount{Balance: big.NewInt(1000000000000000000)} // 1 eth
client := backends.NewSimulatedBackend(gAlloc, 1000000000000000000) // 1 eth
return deployerAuth, client
}
versions are
$ solc --version
solc, the solidity compiler commandline interface
Version: 0.8.9+commit.e5eed63a.Linux.g++
$ abigen --version
abigen version 1.10.0-stable
a snippet of my go.mod
module experiments/solidity_varint
go 1.17
require github.com/ethereum/go-ethereum v1.10.0
...
output of running the main is:
EncodeVarint [10]
EncodeVarintAssemblyNomstore8 [0]
panic: out of gas
goroutine 1 [running]:
main.main()
/home/giulio/go/src/experiments/solidty_varint/main.go:34 +0x24b
exit status 2
Apparently the mstore8
instruction makes the whole call goes out of gas. Is there any reason?? Where is the error in my mstore8
assembly call?
Note:
This varint
functions are decoding function for a protobuf solidity runtime decoder I am working with/on