SNS.yaml: month and year conversion to seconds

For fields that represent duration values, what are the numbers of seconds used to convert months and years provided in the SNS.yaml file?

According documentation of the SNS.yaml example it’s

- months, month, M -- defined as 30.44 days
- years, year, y -- defined as 365.25 days

However when I use 2630016, i.e. 30.44 days, for months and try to propose the WaterNeuron SNS yaml I get an issue that the dissolve_delay_seconds exceeds the limit of 94_672_800 because for 36 months I get 94_680_576.

So you should be using something else than 30.44 days unless 30.44 days is not 2630016 seconds.

2 Likes

I found this piece of code in a foundation repo:

// A few helper constants for durations.
pub const ONE_DAY_SECONDS: u64 = 24 * 60 * 60;
pub const ONE_YEAR_SECONDS: u64 = (4 * 365 + 1) * ONE_DAY_SECONDS / 4;
pub const ONE_MONTH_SECONDS: u64 = ONE_YEAR_SECONDS / 12;

So it seems that 2629800 is used for a month in second and 31557600 for a year.

While it resolve most differences, but I still got issues with the dissolve delays.

Voting:
    minimum_dissolve_delay: 3 months

    VestingSchedule:
        interval: 6 months

However for such a distribution I got the correct amount of seconds:

          principal: g...
          stake: 1_500_000 tokens
          memo: 2
          dissolve_delay: 12 months
          vesting_period: 6 months

Is there somehow two different number of seconds for month and year used by the NNS governance?

Excellent question! The CLI uses the humantime crate for duration parsing. The result of this is the period of time parsed to a rust Duration object. Then we convert it to seconds using Duration::as_secs(), but at this point the number of seconds corresponding to a month is already determined by humantime (rust durations are simply a number of seconds and a number of nanoseconds).

We can see the number of seconds that correspond to various humantime-understood units in the humantime source code here. Particularly, it seems like a month is 2_630_016 seconds, a year is 31_557_600 seconds, a day is 86_400 seconds and a week is seven times that.

So it seems that there are two different number of seconds for month and year used by the NNS governance. In particular the definition of a month is slightly different. The documentation seems correct to me however.

I think you already know, but here is an explanation of the error for others who are curious. The maximal dissolve delay for a neuron an SNS participant receives is: the vesting schedule specified in the CreateServiceNervousSystem times the number of neurons each SNS participant receives. This is because, with a dissolve delay of 1 month and each participant receiving 8 neurons, they would get one neuron with a dissolve delay of one month, a second neuron with a dissolve delay of two months, and so on up to the eighth neuron having a dissolve delay of 8 months. Now if you imagine that the SNS’s maximum dissolve delay is configured to be 5 months, this would create a problem as the sixth, seventh and eighth neuron could not be constructed. This check is implemented here, although it is written in terms of the SnsInitPayload rather than the CreateServiceNervousSystem proposal for historical reasons.

Let me know if this doesn’t completely answer your question.

Thanks for the explanation; however, I have to say that something is definitely off, in my opinion. I doubt that humantime is used out of the box to submit the proposal.

I have tested the WaterNeuron YAML file many times and compared the outcome with the proposal submitted on mainnet. There is no valid scenario in which 2_630_016 seconds is used. Assuming the dissolve delay is a particular case, the only scenario in which I can reproduce the value submitted on mainnet is using 2_629_800 seconds for a human-readable month provided in the YAML file.

Therefore, I see two scenarios:

  • Either the YAML file provided in the WaterNeuron repo is not exactly using the values used to submit the duration of the proposal

or

  • There is an additional conversion in the foundation’s code or a bug

Either way, I’m becoming absolutely mental about those seconds, so I would love to be pointed to the exact piece of code used by the foundation to read the YAML data and generate the NNS proposal.

The code for duration parsing is here.

Most of the rest of the code for generating the CreateServiceNervousSystem is here.

My guess is that the YAML file provided in the WaterNeuron repo is not exactly the one that was used to submit the proposal. I believe there was another case of this mentioned in another forum post recently. If you link me to the waterneuron repo’s YAML file, I can share the exact CreateServiceNervousSystem proposal it would generate and we could compare it against that.

Thanks for the details. It appears that NNS and SNS are using different references in terms of seconds for months and years.

For months, NNS seems to use 2_629_800 seconds, but SNS uses a human-readable crate value of 2_630_016 seconds.

I assume that in both cases, I can multiply by 12 to get the value for a year.

However, I do not know which fields of the SNS.yaml file should be calculated with the first value and which should be calculated with the second value.

Can you provide such information?

As far as I tested by comparing solely the proposal generated locally and on mainnet for CYCLES-TRANSFER-STATION, the following SNS.yaml fields require to be calculated with SNS seconds:

  • Distribution.Neurons.dissolve_delay
  • Distribution.Neurons.vesting_period
  • Voting.minimum_dissolve_delay

And by SNS seconds I mean using the humanreadble create values, i.e.

const snsUnitsToSeconds: Record<string, number> = {
	months: 2_630_016, // 30.44d = 2_630_016
	years: 31_557_600, // 365.25d = 31_557_600
};

Every other duration fields of the SNS.yaml file seem to have to be calculated with NNS seconds, i.e.

const ONE_DAY_SECONDS = 24 * 60 * 60;
const ONE_YEAR_SECONDS = ((4 * 365 + 1) * ONE_DAY_SECONDS) / 4;
const ONE_MONTH_SECONDS = ONE_YEAR_SECONDS / 12;

const nnsUnitsToSeconds: Record<string, number> = {
	months: ONE_MONTH_SECONDS, // 2629800
	years: ONE_YEAR_SECONDS, // 2629800 * 12
};

Can you please confirm or let me know which other fields require “SNS seconds”?

My guess is that the YAML file provided in the WaterNeuron repo is not exactly the one that was used to submit the proposal.

+1

I believe there was another case of this mentioned in another forum post recently. If you link me to the waterneuron repo’s YAML file, I can share the exact CreateServiceNervousSystem proposal it would generate and we could compare it against that.

See here SNS.yaml: start_time format space - #2 by aterga

Thanks for the details. It appears that NNS and SNS are using different references in terms of seconds for months and years.

This is correct. We discussed this issue at some point with the NNS team, but I don’t remember the reasoning behind our decision to keep this unchanged. Maybe @daniel-wong remembers the outcome of that discussion?

I don’t mind about it being unchanged, on the other side, as I shared in my previous question, I would like to know which fields use which types of seconds.

Otherwise I cannot really implement a feature that aim to submit SNS proposal as calculation of the temporality won’t be accurate.

@peterparker

As best as I can recall (i.e. without re-reading the code right now)…

Yes, different parts of the system use different definitions for the length of a “month”. It would not surprise me if there are also different definitions of “year”. This is a bug that we’ve known about for a while. It is not ideal, but we haven’t fixed it yet, because the difference(s) are small, and they do not seem “very harmful”.

When interpreting an sns.yaml file, the same definition of month and year are used consistently throughout. However, it sounds like you are experiencing otherwise. Not sure what discrepancy you are seeing. Can you share an sns.yaml file where 1 month in one field is equal to X seconds, but 1 month in another field equals Y seconds (where Y ≠ X)?