From 2ffc2dc2f1ffa7b5d46222aae409e37974b66c4b Mon Sep 17 00:00:00 2001 From: Anatoliy Dutchak Date: Sat, 14 Sep 2024 05:12:06 +0200 Subject: [PATCH 1/3] Grc 243 migrate static aws credentials (#3386) --- .github/workflows/build-linux-binaries.yml | 6 ++++++ .github/workflows/build-macos-release.yml | 3 +++ .github/workflows/build-public-ami.yml | 3 +++ .github/workflows/build-ubuntu-amd64-release.yml | 6 ++++++ .github/workflows/build-ubuntu-arm64-release.yml | 6 ++++++ .github/workflows/build-win-release.yml | 4 ++++ 6 files changed, 28 insertions(+) diff --git a/.github/workflows/build-linux-binaries.yml b/.github/workflows/build-linux-binaries.yml index f4dcbd93bbf1..c59192883c0a 100644 --- a/.github/workflows/build-linux-binaries.yml +++ b/.github/workflows/build-linux-binaries.yml @@ -13,6 +13,9 @@ on: jobs: build-x86_64-binaries-tarball: runs-on: ubuntu-20.04 + permissions: + id-token: write + contents: read steps: - uses: actions/checkout@v4 @@ -72,6 +75,9 @@ jobs: build-arm64-binaries-tarball: runs-on: custom-arm64-focal + permissions: + id-token: write + contents: read steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build-macos-release.yml b/.github/workflows/build-macos-release.yml index 8f1801b0c1f9..62856e8131da 100644 --- a/.github/workflows/build-macos-release.yml +++ b/.github/workflows/build-macos-release.yml @@ -19,6 +19,9 @@ jobs: build-mac: # The type of runner that the job will run on runs-on: macos-12 + permissions: + id-token: write + contents: read # Steps represent a sequence of tasks that will be executed as part of the job steps: diff --git a/.github/workflows/build-public-ami.yml b/.github/workflows/build-public-ami.yml index d97f7c32395e..bfb1629e425e 100644 --- a/.github/workflows/build-public-ami.yml +++ b/.github/workflows/build-public-ami.yml @@ -18,6 +18,9 @@ jobs: build-public-ami-and-upload: runs-on: ubuntu-22.04 timeout-minutes: 45 + permissions: + id-token: write + contents: read steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build-ubuntu-amd64-release.yml b/.github/workflows/build-ubuntu-amd64-release.yml index 6df99f50979a..6d6514584f01 100644 --- a/.github/workflows/build-ubuntu-amd64-release.yml +++ b/.github/workflows/build-ubuntu-amd64-release.yml @@ -13,6 +13,9 @@ on: jobs: build-jammy-amd64-package: runs-on: ubuntu-22.04 + permissions: + id-token: write + contents: read steps: - uses: actions/checkout@v4 @@ -70,6 +73,9 @@ jobs: build-focal-amd64-package: runs-on: ubuntu-20.04 + permissions: + id-token: write + contents: read steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build-ubuntu-arm64-release.yml b/.github/workflows/build-ubuntu-arm64-release.yml index f78151311fdc..0443487b55e4 100644 --- a/.github/workflows/build-ubuntu-arm64-release.yml +++ b/.github/workflows/build-ubuntu-arm64-release.yml @@ -13,6 +13,9 @@ on: jobs: build-jammy-arm64-package: runs-on: custom-arm64-jammy + permissions: + id-token: write + contents: read steps: - uses: actions/checkout@v4 @@ -70,6 +73,9 @@ jobs: build-focal-arm64-package: runs-on: custom-arm64-focal + permissions: + id-token: write + contents: read steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build-win-release.yml b/.github/workflows/build-win-release.yml index a1d6d1a510d4..d882fe4aadd9 100644 --- a/.github/workflows/build-win-release.yml +++ b/.github/workflows/build-win-release.yml @@ -19,6 +19,10 @@ jobs: build-win: # The type of runner that the job will run on runs-on: windows-2019 + permissions: + id-token: write + contents: read + # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it From 69efca3ee124ed1c9ce41860f59680724fc93c49 Mon Sep 17 00:00:00 2001 From: cocoyeal <150209682+cocoyeal@users.noreply.github.com> Date: Sun, 15 Sep 2024 22:40:00 +0800 Subject: [PATCH 2/3] chore: fix comment (#3389) Signed-off-by: cocoyeal <150209682+cocoyeal@users.noreply.github.com> --- proto/pb/sdk/sdk.pb.go | 2 +- proto/sdk/sdk.proto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/proto/pb/sdk/sdk.pb.go b/proto/pb/sdk/sdk.pb.go index a1289d391032..b774940a3e8d 100644 --- a/proto/pb/sdk/sdk.pb.go +++ b/proto/pb/sdk/sdk.pb.go @@ -229,7 +229,7 @@ func (x *SignatureRequest) GetJustification() []byte { return nil } -// SignatureRespnose is an AppResponse message type for providing +// SignatureResponse is an AppResponse message type for providing // a requested BLS signature over a Warp message, as defined in ACP-118: // https://github.com/avalanche-foundation/ACPs/tree/main/ACPs/118-warp-signature-request type SignatureResponse struct { diff --git a/proto/sdk/sdk.proto b/proto/sdk/sdk.proto index d4eea3d5d085..4e660d3c1166 100644 --- a/proto/sdk/sdk.proto +++ b/proto/sdk/sdk.proto @@ -27,7 +27,7 @@ message SignatureRequest { bytes justification = 2; } -// SignatureRespnose is an AppResponse message type for providing +// SignatureResponse is an AppResponse message type for providing // a requested BLS signature over a Warp message, as defined in ACP-118: // https://github.com/avalanche-foundation/ACPs/tree/main/ACPs/118-warp-signature-request message SignatureResponse { From d660979df5fdde3208c792f0303651f80936c684 Mon Sep 17 00:00:00 2001 From: Stephen Buttolph Date: Wed, 18 Sep 2024 15:43:44 -0400 Subject: [PATCH 3/3] ACP-77: Update `SecondsUntil` to prevent under-charging (#3395) --- vms/platformvm/validators/fee/fee.go | 67 +++----- vms/platformvm/validators/fee/fee_test.go | 181 +++++++++++++++++----- 2 files changed, 164 insertions(+), 84 deletions(-) diff --git a/vms/platformvm/validators/fee/fee.go b/vms/platformvm/validators/fee/fee.go index be0eae544ea2..23705d8b25a2 100644 --- a/vms/platformvm/validators/fee/fee.go +++ b/vms/platformvm/validators/fee/fee.go @@ -43,7 +43,7 @@ func (s State) AdvanceTime(target gas.Gas, seconds uint64) State { } // CostOf calculates how much to charge based on the dynamic fee mechanism for -// [seconds]. +// seconds. // // This implements the ACP-77 cost over time formula: func (s State) CostOf(c Config, seconds uint64) uint64 { @@ -91,35 +91,24 @@ func (s State) CostOf(c Config, seconds uint64) uint64 { return cost } -// SecondsUntil calculates the number of seconds that it would take to charge at -// least [targetCost] based on the dynamic fee mechanism. The result is capped -// at [maxSeconds]. -func (s State) SecondsUntil(c Config, maxSeconds uint64, targetCost uint64) uint64 { +// SecondsRemaining calculates the maximum number of seconds that a validator +// can pay fees before their fundsRemaining would be exhausted based on the +// dynamic fee mechanism. The result is capped at maxSeconds. +func (s State) SecondsRemaining(c Config, maxSeconds uint64, fundsRemaining uint64) uint64 { // Because this function can divide by prices, we need to sanity check the // parameters to avoid division by 0. if c.MinPrice == 0 { - if targetCost == 0 { - return 0 - } return maxSeconds } // If the current and target are the same, the price is constant. if s.Current == c.Target { - price := gas.CalculatePrice(c.MinPrice, s.Excess, c.ExcessConversionConstant) - return secondsUntil( - uint64(price), - maxSeconds, - targetCost, - ) + price := uint64(gas.CalculatePrice(c.MinPrice, s.Excess, c.ExcessConversionConstant)) + seconds := fundsRemaining / price + return min(seconds, maxSeconds) } - var ( - cost uint64 - seconds uint64 - err error - ) - for cost < targetCost && seconds < maxSeconds { + for seconds := uint64(0); seconds < maxSeconds; seconds++ { s = s.AdvanceTime(c.Target, 1) // Advancing the time is going to either hold excess constant, @@ -127,41 +116,21 @@ func (s State) SecondsUntil(c Config, maxSeconds uint64, targetCost uint64) uint // equal to 0 after performing one of these operations, it is guaranteed // to always remain 0. if s.Excess == 0 { - zeroExcessCost := targetCost - cost - secondsWithZeroExcess := secondsUntil( - uint64(c.MinPrice), - maxSeconds, - zeroExcessCost, - ) - + secondsWithZeroExcess := fundsRemaining / uint64(c.MinPrice) totalSeconds, err := safemath.Add(seconds, secondsWithZeroExcess) - if err != nil || totalSeconds >= maxSeconds { + if err != nil { + // This is technically unreachable, but makes the code more + // clearly correct. return maxSeconds } - return totalSeconds + return min(totalSeconds, maxSeconds) } - seconds++ - price := gas.CalculatePrice(c.MinPrice, s.Excess, c.ExcessConversionConstant) - cost, err = safemath.Add(cost, uint64(price)) - if err != nil { + price := uint64(gas.CalculatePrice(c.MinPrice, s.Excess, c.ExcessConversionConstant)) + if price > fundsRemaining { return seconds } + fundsRemaining -= price } - return seconds -} - -// Calculate the number of seconds that it would take to charge at least [cost] -// at [price] every second. The result is capped at [maxSeconds]. -func secondsUntil(price uint64, maxSeconds uint64, cost uint64) uint64 { - // Directly rounding up could cause an overflow. Instead we round down and - // then check if we should have rounded up. - secondsRoundedDown := cost / price - if secondsRoundedDown >= maxSeconds { - return maxSeconds - } - if cost%price == 0 { - return secondsRoundedDown - } - return secondsRoundedDown + 1 + return maxSeconds } diff --git a/vms/platformvm/validators/fee/fee_test.go b/vms/platformvm/validators/fee/fee_test.go index 059fbad61c51..f99be8682bb6 100644 --- a/vms/platformvm/validators/fee/fee_test.go +++ b/vms/platformvm/validators/fee/fee_test.go @@ -20,7 +20,6 @@ const ( hour = 60 * minute day = 24 * hour week = 7 * day - year = 365 * day minPrice = 2_048 @@ -212,7 +211,7 @@ var ( expectedExcess: math.MaxUint64, // Should not overflow }, { - name: "excess=0, current>>target, 11 seconds", + name: "excess=0, current>>target, 10 seconds", state: State{ Current: math.MaxUint32, Excess: 0, @@ -222,9 +221,9 @@ var ( MinPrice: minPrice, ExcessConversionConstant: excessConversionConstant, }, - expectedSeconds: 11, - expectedCost: math.MaxUint64, // Should not overflow - expectedExcess: math.MaxUint32 * 11, + expectedSeconds: 10, + expectedCost: 1_948_429_840_780_833_612, + expectedExcess: math.MaxUint32 * 10, }, } ) @@ -256,13 +255,131 @@ func TestStateCostOf(t *testing.T) { } } -func TestStateSecondsUntil(t *testing.T) { +func TestStateCostOfOverflow(t *testing.T) { + const target = 10_000 + config := Config{ + Target: target, + MinPrice: minPrice, + ExcessConversionConstant: excessConversionConstant, + } + + tests := []struct { + name string + state State + seconds uint64 + }{ + { + name: "current > target", + state: State{ + Current: math.MaxUint32, + Excess: 0, + }, + seconds: math.MaxUint64, + }, + { + name: "current == target", + state: State{ + Current: target, + Excess: 0, + }, + seconds: math.MaxUint64, + }, + { + name: "current < target", + state: State{ + Current: 0, + Excess: 0, + }, + seconds: math.MaxUint64, + }, + { + name: "current < target and reasonable excess", + state: State{ + Current: 0, + Excess: target + 1, + }, + seconds: math.MaxUint64/minPrice + 1, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + require.Equal( + t, + uint64(math.MaxUint64), // Should not overflow + test.state.CostOf(config, test.seconds), + ) + }) + } +} + +func TestStateSecondsRemaining(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { require.Equal( t, test.expectedSeconds, - test.state.SecondsUntil(test.config, year, test.expectedCost), + test.state.SecondsRemaining(test.config, week, test.expectedCost), + ) + }) + } +} + +func TestStateSecondsRemainingLimit(t *testing.T) { + const target = 10_000 + tests := []struct { + name string + state State + minPrice gas.Price + costLimit uint64 + }{ + { + name: "zero price", + state: State{ + Current: math.MaxUint32, + Excess: 0, + }, + minPrice: 0, + costLimit: 0, + }, + { + name: "current > target", + state: State{ + Current: target + 1, + Excess: 0, + }, + minPrice: minPrice, + costLimit: math.MaxUint64, + }, + { + name: "current == target", + state: State{ + Current: target, + Excess: 0, + }, + minPrice: minPrice, + costLimit: minPrice * (week + 1), + }, + { + name: "current < target", + state: State{ + Current: 0, + Excess: 0, + }, + minPrice: minPrice, + costLimit: minPrice * (week + 1), + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + config := Config{ + Target: target, + MinPrice: test.minPrice, + ExcessConversionConstant: excessConversionConstant, + } + require.Equal( + t, + uint64(week), + test.state.SecondsRemaining(config, week, test.costLimit), ) }) } @@ -299,10 +416,10 @@ func BenchmarkStateCostOf(b *testing.B) { } } -func BenchmarkStateSecondsUntil(b *testing.B) { +func BenchmarkStateSecondsRemaining(b *testing.B) { benchmarks := []struct { - name string - secondsUntil func( + name string + secondsRemaining func( s State, c Config, maxSeconds uint64, @@ -310,12 +427,12 @@ func BenchmarkStateSecondsUntil(b *testing.B) { ) uint64 }{ { - name: "unoptimized", - secondsUntil: State.unoptimizedSecondsUntil, + name: "unoptimized", + secondsRemaining: State.unoptimizedSecondsRemaining, }, { - name: "optimized", - secondsUntil: State.SecondsUntil, + name: "optimized", + secondsRemaining: State.SecondsRemaining, }, } for _, test := range tests { @@ -323,7 +440,7 @@ func BenchmarkStateSecondsUntil(b *testing.B) { for _, benchmark := range benchmarks { b.Run(benchmark.name, func(b *testing.B) { for i := 0; i < b.N; i++ { - benchmark.secondsUntil(test.state, test.config, year, test.expectedCost) + benchmark.secondsRemaining(test.state, test.config, week, test.expectedCost) } }) } @@ -361,7 +478,7 @@ func FuzzStateCostOf(f *testing.F) { MinPrice: gas.Price(minPrice), ExcessConversionConstant: gas.Gas(max(excessConversionConstant, 1)), } - seconds = min(seconds, year) + seconds = min(seconds, hour) require.Equal( t, s.unoptimizedCostOf(c, seconds), @@ -371,7 +488,7 @@ func FuzzStateCostOf(f *testing.F) { ) } -func FuzzStateSecondsUntil(f *testing.F) { +func FuzzStateSecondsRemaining(f *testing.F) { for _, test := range tests { f.Add( uint64(test.state.Current), @@ -379,7 +496,7 @@ func FuzzStateSecondsUntil(f *testing.F) { uint64(test.config.Target), uint64(test.config.MinPrice), uint64(test.config.ExcessConversionConstant), - uint64(year), + uint64(hour), test.expectedCost, ) } @@ -403,11 +520,11 @@ func FuzzStateSecondsUntil(f *testing.F) { MinPrice: gas.Price(minPrice), ExcessConversionConstant: gas.Gas(max(excessConversionConstant, 1)), } - maxSeconds = min(maxSeconds, year) + maxSeconds = min(maxSeconds, hour) require.Equal( t, - s.unoptimizedSecondsUntil(c, maxSeconds, targetCost), - s.SecondsUntil(c, maxSeconds, targetCost), + s.unoptimizedSecondsRemaining(c, maxSeconds, targetCost), + s.SecondsRemaining(c, maxSeconds, targetCost), ) }, ) @@ -432,25 +549,19 @@ func (s State) unoptimizedCostOf(c Config, seconds uint64) uint64 { return cost } -// unoptimizedSecondsUntil is a naive implementation of SecondsUntil that is -// used for differential fuzzing. -func (s State) unoptimizedSecondsUntil(c Config, maxSeconds uint64, targetCost uint64) uint64 { - var ( - cost uint64 - seconds uint64 - err error - ) - for cost < targetCost && seconds < maxSeconds { +// unoptimizedSecondsRemaining is a naive implementation of SecondsRemaining +// that is used for differential fuzzing. +func (s State) unoptimizedSecondsRemaining(c Config, maxSeconds uint64, fundsRemaining uint64) uint64 { + for seconds := uint64(0); seconds < maxSeconds; seconds++ { s = s.AdvanceTime(c.Target, 1) - seconds++ - price := gas.CalculatePrice(c.MinPrice, s.Excess, c.ExcessConversionConstant) - cost, err = safemath.Add(cost, uint64(price)) - if err != nil { + price := uint64(gas.CalculatePrice(c.MinPrice, s.Excess, c.ExcessConversionConstant)) + if price > fundsRemaining { return seconds } + fundsRemaining -= price } - return seconds + return maxSeconds } // floatToGas converts f to gas.Gas by truncation. `gas.Gas(f)` is preferred and