Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Oct 10 2017 22:42
    @jpitts banned @etherchamp1_twitter
  • Jun 05 2016 10:33
    @chriseth banned @adamskee
Remi Burgel
@Remi-Burgel
Why do uint8 even exists if it's real ?
Nick Johnson
@Arachnid
In contract storage, smaller variables can be packed together, so they use less than a word of storage each.
Smaller values are also truncated, so you have guarantees as to their range.
But in general you're right that often it does not make sense to use a smaller value.
Remi Burgel
@Remi-Burgel
Ok thanks, I will try to pack them
Because I have a big struct in my contract
Nick Johnson
@Arachnid

I don't mean that you have to pack them manually. I mean that if you specify a struct like this:

struct foo {
  uint8 a;
  uint8 b;
}

then Solidity will pack both into the same word of storage for you.

Remi Burgel
@Remi-Burgel
Nice !
But if i do
struct foo {
    uint8 a
    address b
    uint8 b
}
It will be less optimal than packing them in the declaration right ?
Nick Johnson
@Arachnid
That's right - but if you reorder them so the uint8s are adjacent, they will pack again.
Remi Burgel
@Remi-Burgel
nice !
thank you for your help
Nick Johnson
@Arachnid
No problem
Remi Burgel
@Remi-Burgel

Very specific question, if you have an idea without testing if I do :

        address a;
        uint16 b;
        uint16 c;
        uint32 d;
        uint32 e;
        uint32 f;
        uint32 g;
        uint32 h;
        uint32 i;

Is it more or less optimal than

        address a;
        uint32 b;
        uint32 c;
        uint32 d;
        uint32 e;
        uint32 f;
        uint32 g;
        uint32 h;
        uint32 i;

?

(in a struct in my case)
Nick Johnson
@Arachnid
The latter will probably be larger; you can pack a 20 byte address, two 2 byte uint16s and two 4-byte uint32 into one word.
Oh, I guess they'll be the same, actually, just packed differently.
Remi Burgel
@Remi-Burgel
mmm ok, ok
But if you can pack addresses with uint
(uint16)
why was my first example not optimal ?
struct foo {
    uint8 a
    address b
    uint8 b
}
this one
Nick Johnson
@Arachnid
I was probably mistaken on that; it may well be able to pack them all into one word.
Martin Holst Swende
@holiman
@phalexo yes the 20 bytes following a push20 is not code. The pc jumps over them.
Evm code has basically data-sections and code-sections.
Data always and only follow after pushX ops
phalexo
@phalexo
@holiman That is what I had surmised but wanted to make sure there is not some magic going on behind the scenes.
So, I can just follow the same pattern then, oring the value into the mstore's parameter.
phalexo
@phalexo
And I can access an _uniqueID's value the same way you access a contract's address a.
phalexo
@phalexo

@holiman

function clone(address _contractAddress,  address _creatorAddress, uint4 _uniqueId)  {
    address retval;
    assembly {
        mstore(0x0, or (0x5880730000000000000000000000000000000000000000803b80938091923c77, mul(_contractAddress, 0x1000000000000000000)))
        mstore(0x20, or (0x00000000000000000000000000000000000000000000000082529060200190F3 , mul( or (mul(_creatorAddress, 0x100000000), _uniqueId), 0x10000000000000000)))
        retval := create(0,0, 64)
    }
    return retval;
 }

This is what I got so far. I have not tried to run it yet.

Martin Holst Swende
@holiman
Try running the raw initcode and get that working on its own.. at least , that's what I'd do
phalexo
@phalexo
It looks reasonable though, right?
@holiman I used the last byte in the first 32 byte slot to do PUSH24 to account for 20 bytes of the creator address and 4 byte integer tag. So the 24 bytes of data get stored at position 0 in the second mstore. Using the entire 32 bytes of the second slot for something useful.
Martin Holst Swende
@holiman
@phalexo I coded this up as an example in evmlab: https://github.com/holiman/evmlab/blob/master/initcode.py
#python3 initcode.py 
Bytecode:  60008073123456789a123456789a123456789a123456789a803b80938091923c61133882529060200190f3
/home/martin/go/src/github.com/ethereum/go-ethereum/build/bin/evm --code 60008073123456789a123456789a123456789a123456789a803b80938091923c61133882529060200190f3 --prestate /tmp/genesis-genesis-geth_5oQI3Twu.json --gas 65535 --json run
PUSH1  []
DUP1  ['0x0']
PUSH20  ['0x0', '0x0']
DUP1  ['0x0', '0x0', '0x123456789a123456789a123456789a123456789a']
EXTCODESIZE  ['0x0', '0x0', '0x123456789a123456789a123456789a123456789a', '0x123456789a123456789a123456789a123456789a']
DUP1  ['0x0', '0x0', '0x123456789a123456789a123456789a123456789a', '0x2']
SWAP4  ['0x0', '0x0', '0x123456789a123456789a123456789a123456789a', '0x2', '0x2']
DUP1  ['0x2', '0x0', '0x123456789a123456789a123456789a123456789a', '0x2', '0x0']
SWAP2  ['0x2', '0x0', '0x123456789a123456789a123456789a123456789a', '0x2', '0x0', '0x0']
SWAP3  ['0x2', '0x0', '0x123456789a123456789a123456789a123456789a', '0x0', '0x0', '0x2']
EXTCODECOPY  ['0x2', '0x0', '0x2', '0x0', '0x0', '0x123456789a123456789a123456789a123456789a']
PUSH2  ['0x2', '0x0']
DUP3  ['0x2', '0x0', '0x1338']
MSTORE  ['0x2', '0x0', '0x1338', '0x2']
SWAP1  ['0x2', '0x0']
PUSH1  ['0x0', '0x2']
ADD  ['0x0', '0x2', '0x20']
SWAP1  ['0x0', '0x22']
RETURN  ['0x22', '0x0']
{"output":"13370000000000000000000000000000000000000000000000000000000000001338","gasUsed":"0x5b1","time":319959}
It's a pretty nifty toolset to experiment with evm assembly
Martin Holst Swende
@holiman
It was hardcoded to use 32 byte identifier, so replacing 1338 with an actual 32-byte value yields:
{"output":"1337deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef","gasUsed":"0x5b1","time":414448}
So that seems to work. Now you can 'golf' it down further, and experiment with various mods
You can check out my devcon-talk for some more goodies within evmlab
phalexo
@phalexo
I browsed it, can it attach to a running geth instance or it needs to run its own? Can it use testrpc?
Martin Holst Swende
@holiman
It uses either a raw evm, which you get if you do make all inside a go-ethereum source folder. or you can specify a docker evm
Change this:
#    geth = vm.GethVM("/home/martin/go/src/github.com/ethereum/go-ethereum/build/bin/evm")
    geth = vm.GethVM("holiman/gethvm", docker=True)
May have to docker pull holiman/gethvm, otherwise it'll time out trying to download it within evmlab
(if you do make all, it'll land within 'build/bin')
phalexo
@phalexo
I have a geth running inside a docker for Rinkeby, or mainnet, exposing geth.ipc or rpc on the 8545 port.
Martin Holst Swende
@holiman
No
This does not use geth, this uses evm
evm is a standalone binary, the heart of geth