Open jnordberg opened 3 years ago
Google takes me here. Though it may be out of topic, I'd like to share my experience. In C++ Smart Contracts if you sort public_key vector directly, you will not get what you want.
The following example works:
bool sort_public_key (public_key a, public_key b) {
const auto& a1 = std::get<0>(a);
const auto& b1 = std::get<0>(b);
return memcmp(a1.data(), b1.data(), 33) < 0;
}
vector<public_key> keys;
sort(keys.begin(), keys.end(), sort_public_key);
In TS, base58 representation of public key sorting works too, don't worry about it.
For lexographic comparison of K1 and R1 keys in JS/TS, I have been using localeCompare
so far, but it breaks with WA keys, the following example will error in updateauth
:
"EOS5fMyAUopVJv88Wb4szbLH2ds65jiNCjv1XWRRyvrfR6oEBdZXk",
"PUB_WA_323xpHU17pKZ6VsygcdXxq7cgosxSyRU5KGevyjUNtw4m9Y63EzPs3SEVpsf7rjeVLa7",
"PUB_WA_4B6ZbE2hxTvcrndvS8758EjGqRMQqVoV4vBTGgvqi27HNw8xyQz6viKrGLNLcaiRmhmbuyu584Hf",
"PUB_WA_4vD5irsd1GdmTEhea5G8QideW3NqU8F5zgPLyD3wKDE7MUPAwo5nELCEbJEELDafLeV4Uz7djSFJ",
"PUB_WA_5Q6G5dqajZDkqDbgEUG7a7qMpe94P6LegYdf7h8yL9efjhC6ERWuFsJM1ueygEmXzaELBokrUeH8",
"PUB_WA_6wUAAJXLFc3edKhGb5DdWb3WmoLxLwFSspdiEYHvT6DN2X7zo6opCfv6TcAifvxRQdVYwcr84zMS"
@learnforpractice
Btw there is a sort() helper on the Authority type that will do the locale compare hack but will break on updates that have multiple WA keys as you pointed out
As I was said, in C++, you need to use memcmp to sort public keys.
K1 and R1 keys are both stored in 34 bytes in C++.
If the first byte is 0, it’s a K1 key. If the first byte is 1, it’s an R1 key.
In TS, the following method may work to sort keys combine with K1 and R1:
const a = new Uint8Array([3, 1, 3, 5]) const b = new Uint8Array([1, 3, 2])
function compare(a: Uint8Array, b: Uint8Array) { let size = a.length; if (size > b.length) { size = b.length }
for (let i=0; i<size; i++) {
let diff = a[i] - b[i]
if (diff == 0) {
continue
}
return diff
}
return a.length - b.length
}
let aa = [a, b] aa.sort(compare)
On Jan 24, 2022, at 3:07 PM, Syed Jafri @.***> wrote:
For lexographic comparison of K1 and R1 keys, I have been using localeCompare so far, but it breaks with WA keys, example:
"EOS5fMyAUopVJv88Wb4szbLH2ds65jiNCjv1XWRRyvrfR6oEBdZXk", "PUB_WA_323xpHU17pKZ6VsygcdXxq7cgosxSyRU5KGevyjUNtw4m9Y63EzPs3SEVpsf7rjeVLa7", "PUB_WA_4B6ZbE2hxTvcrndvS8758EjGqRMQqVoV4vBTGgvqi27HNw8xyQz6viKrGLNLcaiRmhmbuyu584Hf", "PUB_WA_4vD5irsd1GdmTEhea5G8QideW3NqU8F5zgPLyD3wKDE7MUPAwo5nELCEbJEELDafLeV4Uz7djSFJ", "PUB_WA_5Q6G5dqajZDkqDbgEUG7a7qMpe94P6LegYdf7h8yL9efjhC6ERWuFsJM1ueygEmXzaELBokrUeH8", "PUB_WA_6wUAAJXLFc3edKhGb5DdWb3WmoLxLwFSspdiEYHvT6DN2X7zo6opCfv6TcAifvxRQdVYwcr84zMS" — Reply to this email directly, view it on GitHub https://github.com/greymass/eosio-core/issues/8#issuecomment-1019782068, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHPJSPW2C4OQA7CWZEVXPQDUXT3EZANCNFSM4WW6HIPQ. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you commented.
@learnforpractice The issue is the WA key type, your memcmp method would likely fail as well if the array contained keys of that type since the keydata contains a string that packs its own length as a varuint prefix
Yeah, the first byte of WA key is 2, and the raw WA key size is not fixed to 34. The following python code demonstrates how to sort keys combined with K1, R1, and WA which can easily be ported to TS I think.
import base58 pub_keys = [ "PUB_WA_323xpHU17pKZ6VsygcdXxq7cgosxSyRU5KGevyjUNtw4m9Y63EzPs3SEVpsf7rjeVLa7", "PUB_WA_4B6ZbE2hxTvcrndvS8758EjGqRMQqVoV4vBTGgvqi27HNw8xyQz6viKrGLNLcaiRmhmbuyu584Hf", "PUB_WA_4vD5irsd1GdmTEhea5G8QideW3NqU8F5zgPLyD3wKDE7MUPAwo5nELCEbJEELDafLeV4Uz7djSFJ", "PUB_WA_5Q6G5dqajZDkqDbgEUG7a7qMpe94P6LegYdf7h8yL9efjhC6ERWuFsJM1ueygEmXzaELBokrUeH8", "PUB_K1_518vvdSbDRUkPTXhMaGf2hNGN8RPvHGXdkr2YDsLPh81sS6DGm", "EOS7RWp93PBkwDKjNRroTrA5rYV1c7RcbwbZVUXD8PBArQTQwMB9G" ]
def get_key(pub_key): if pub_key.startswith('PUBK1'): return b'\x00' + base58.b58decode(pub_key.removeprefix('PUBK1'))[:-4] if pub_key.startswith('EOS'): return b'\x00' + base58.b58decode(pub_key.removeprefix('EOS'))[:-4] elif pub_key.startswith('PUBR1'): return b'\x01' + base58.b58decode(pub_key.removeprefix('PUBR1'))[:-4] elif pub_key.startswith('PUBWA'): return b'\x02' + base58.b58decode(pub_key.removeprefix('PUBWA'))[:-4] else: assert False, 'unknown pubkey format'
pub_keys = sorted(pub_keys, key=get_key) print(pub_keys)
On Jan 24, 2022, at 4:13 PM, Johan Nordberg @.***> wrote:
@learnforpractice https://github.com/learnforpractice The issue is the WA key type, your memcmp method would likely fail as well if the array contained keys of that type since the keydata contains a string that packs its own length as a varuint prefix
— Reply to this email directly, view it on GitHub https://github.com/greymass/eosio-core/issues/8#issuecomment-1019825178, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHPJSPRWXCI3G7VHC6E5J3DUXUC3RANCNFSM4WW6HIPQ. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.
To update an accounts permissions nodeos enforces that the keys are sorted, the sorting logic comes from the fc library and has to be re-created for every type involved. Fortunately due to a quirk of how it is implemented for 99% of cases we can get away with sorting the string representations of the types in question.
For now the Authority type will use the string sorting hack. But long-term we should add a
compare
requirement to all core types and replicate fc's sorting behavior for all of them.Attaching chat log from Telegram discussing this for posterity