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