johguse / profanity

Vanity address generator for Ethereum
834 stars 324 forks source link

add mode for gas optimization #63

Open heathdutton opened 2 years ago

heathdutton commented 2 years ago

Based on https://github.com/johguse/profanity/issues/57

plotchy commented 2 years ago

Good work! This is so useful. I wanted to suggest a simpler alternative that in the vast majority of situations saves more gas for a typical user.

The usecase of the 4 leading zero-bytes is to be able to cast an address to a uint128 rather than a uint160. Specifically, if you have 2 of these addresses with 4 leading zero-bytes, you can pack both of them into a single uint256 storage slot. You can take advantage of this in your own custom contracts to parse each address from the front/back of the storage slot and prepend the 8 zeroes afterwards. If you plan on using both addresses frequently in your code, this saves a cool ~2000 gas during runtime in solidity. However, this usecase is extremely niche, and never used in the wild such that a typical user could take advantage.

A more generalized --gas option would be for finding the highest total of zero-bytes within the address. This takes advantage of the much more applicable Gtxdatazero, which saves 12 gas compared to every non-zero byte in the address.

Gtxdatazero | 4 Paid for every zero byte of data or code for a transaction.
Gtxdatanonzero | 16 Paid for every non-zero byte of data or code for a transaction

This allows you to find addresses with more zero-bytes than the more restricting condition that 4 zero-bytes must lead.

__kernel void profanity_score_leading(__global mp_number * const pInverse, __global result * const pResult, __constant const uchar * const data1, __constant const uchar * const data2, const uchar scoreMax) {
    const size_t id = get_global_id(0);
    __global const uchar * const hash = pInverse[id].d;
    int score = 0;

    for (int i = 0; i < 20; ++i) {
        score += (hash[i] == 0);
    }

    profanity_result_update(id, hash, pResult, score, scoreMax);
}
heathdutton commented 2 years ago

You are correct of course! A wallet user only cares about the number of zero bytes probably. I was making contracts, so this worked better for my needs at the time.

definevalue commented 2 years ago

Can you elaborate a bit more on the making contracts? Because doing a contract with less bytes also utilizes less gas too? I'm only asking because If theres something more useful that i'm not seeing here I would love the insight or at least a point in the direction that your utilizing it for.

heathdutton commented 2 years ago

To @plotchy's point, a more generic gas optimization is better for most cases, so I simplified it.

Leading/trailing/contiguous zero-bytes is generally better for a contract because you can pack it in less bytecode. Think of clone/proxy contracts in particular.

...but... the results took much longer when trying to get to something like that.

I found the generic version was faster and suffices just fine for most cases. Even on my M1 Mac it performs well:

./profanity.x64 --gas --contract -I 20000

Got me:

  Time:    36s Score:  4 Private: ...
  Time:    36s Score:  5 Private: ...
  Time:   635s Score:  6 Private: ...
  Time: 42077s Score:  7 Private: ...
  Time: 121087s Score:  8 Private: ...

(granted, this was a bit lucky... still really fantastic!)

definevalue commented 2 years ago

https://eip2535diamonds.substack.com/p/introduction-to-the-diamond-standard and utilizing above references seems fun.