From bdc81e54fdb56735de06b83d1cae9dd1432e1728 Mon Sep 17 00:00:00 2001 From: dtfiedler Date: Thu, 11 Jul 2024 07:10:31 -0600 Subject: [PATCH 1/2] fix(epochs): handle unix timestsamps in ms and convert to seconds This is just precaution to ensure the contract is always dealing in ms --- src/epochs.lua | 3 ++- src/utils.lua | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/epochs.lua b/src/epochs.lua index da0e97c2..c4db2a90 100644 --- a/src/epochs.lua +++ b/src/epochs.lua @@ -227,9 +227,10 @@ function epochs.getEpochTimestampsForIndex(epochIndex) end function epochs.getEpochIndexForTimestamp(timestamp) + local timestampInMS = utils.checkAndConvertTimestamptoMs(timestamp) local epochZeroStartTimestamp = epochs.getSettings().epochZeroStartTimestamp local epochLengthMs = epochs.getSettings().durationMs - local epochIndex = math.floor((timestamp - epochZeroStartTimestamp) / epochLengthMs) + local epochIndex = math.floor((timestampInMS - epochZeroStartTimestamp) / epochLengthMs) return epochIndex end diff --git a/src/utils.lua b/src/utils.lua index b5bc61c1..5623b09e 100644 --- a/src/utils.lua +++ b/src/utils.lua @@ -222,4 +222,30 @@ function utils.splitString(str, delimiter) return result end +function utils.checkAndConvertTimestamptoMs(timestamp) + -- Check if the timestamp is an integer + if type(timestamp) ~= "number" or timestamp % 1 ~= 0 then + return error("Timestamp must be an integer") + end + + -- Define the plausible range for Unix timestamps in seconds + local min_timestamp = 0 + local max_timestamp = 4102444800 -- Corresponds to 2100-01-01 + + if timestamp >= min_timestamp and timestamp <= max_timestamp then + -- The timestamp is already in seconds, convert it to milliseconds + return timestamp * 1000 + end + + -- If the timestamp is outside the range for seconds, check for milliseconds + local min_timestamp_ms = min_timestamp * 1000 + local max_timestamp_ms = max_timestamp * 1000 + + if timestamp >= min_timestamp_ms and timestamp <= max_timestamp_ms then + return timestamp + end + + return error("Timestamp is out of range") +end + return utils From 9930382bfbe643bdff9622e55581ce3da39dff7d Mon Sep 17 00:00:00 2001 From: dtfiedler Date: Thu, 11 Jul 2024 07:37:28 -0600 Subject: [PATCH 2/2] chore(tests): update tests --- spec/epochs_spec.lua | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/spec/epochs_spec.lua b/spec/epochs_spec.lua index d6db010d..d4c2bc82 100644 --- a/spec/epochs_spec.lua +++ b/spec/epochs_spec.lua @@ -11,7 +11,7 @@ local testSettings = { label = "test", delegateRewardShareRatio = 0, } -local startTimestamp = 0 +local startTimestamp = 1704092400000 local protocolBalance = 500000000 * 1000000 local hashchain = "NGU1fq_ssL9m6kRbRU1bqiIDBht79ckvAwRMGElkSOg" -- base64 of "some sample hash" @@ -23,9 +23,9 @@ describe("epochs", function() } _G.Epochs = { [0] = { - startTimestamp = 0, - endTimestamp = 100, - distributionTimestamp = 115, + startTimestamp = 1704092400000, + endTimestamp = 1704092400100, + distributionTimestamp = 1704092400115, prescribedObservers = {}, distributions = {}, observations = { @@ -42,7 +42,7 @@ describe("epochs", function() epochs.updateEpochSettings({ prescribedNameCount = 5, maxObservers = 5, - epochZeroStartTimestamp = 0, + epochZeroStartTimestamp = 1704092400000, -- 2024-01-01T00:00:00.000Z durationMs = 100, distributionDelayMs = 15, rewardPercentage = 0.0025, -- 0.25% @@ -233,7 +233,8 @@ describe("epochs", function() it("should throw an error when saving observation too early in the epoch", function() local observer = "test-this-is-valid-arweave-wallet-address-2" local reportTxId = "test-this-very-valid-observations-report-tx" - local timestamp = 1 + local settings = epochs.getSettings() + local timestamp = settings.epochZeroStartTimestamp + settings.distributionDelayMs - 1 local failedGateways = { "test-this-is-valid-arweave-wallet-address-1", } @@ -244,7 +245,8 @@ describe("epochs", function() it("should throw an error if the caller is not prescribed", function() local observer = "test-this-is-valid-arweave-wallet-address-2" local reportTxId = "test-this-very-valid-observations-report-tx" - local timestamp = epochs.getSettings().distributionDelayMs + 1 + local settings = epochs.getSettings() + local timestamp = settings.epochZeroStartTimestamp + settings.distributionDelayMs + 1 local failedGateways = { "test-this-is-valid-arweave-wallet-address-1", } @@ -271,7 +273,8 @@ describe("epochs", function() function() local observer = "test-this-is-valid-arweave-wallet-address-2" local reportTxId = "test-this-very-valid-observations-report-tx" - local timestamp = epochs.getSettings().distributionDelayMs + 1 + local settings = epochs.getSettings() + local timestamp = settings.epochZeroStartTimestamp + settings.distributionDelayMs + 1 _G.GatewayRegistry = { ["test-this-is-valid-arweave-wallet-address-1"] = { operatorStake = gar.getSettings().operators.minStake, @@ -403,7 +406,7 @@ describe("epochs", function() describe("getEpochTimestampsForIndex", function() it("should return the epoch timestamps for the given epoch index", function() local epochIndex = 0 - local expectation = { 0, 100, 115 } + local expectation = { 1704092400000, 1704092400100, 1704092400115 } local result = { epochs.getEpochTimestampsForIndex(epochIndex) } assert.are.same(result, expectation) end) @@ -413,11 +416,12 @@ describe("epochs", function() it( "should create a new epoch for the given timestamp once distributions for the last epoch have occurred", function() - local timestamp = 100 + local settings = epochs.getSettings() local epochIndex = 1 - local epochStartTimestamp = 100 - local epochEndTimestamp = 200 - local epochDistributionTimestamp = 215 + local epochStartTimestamp = settings.epochZeroStartTimestamp + settings.durationMs + local timestamp = epochStartTimestamp + local epochEndTimestamp = epochStartTimestamp + settings.durationMs + local epochDistributionTimestamp = epochEndTimestamp + settings.distributionDelayMs local epochStartBlockHeight = 0 local expectation = { startTimestamp = epochStartTimestamp,