Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

storagecost_test.gno

6.55 Kb · 195 lines
  1package storagecost
  2
  3import (
  4	"testing"
  5
  6	"gno.land/p/nt/uassert/v0"
  7)
  8
  9func TestRefund(t *testing.T) {
 10	tests := []struct {
 11		name  string
 12		bytes int64
 13		price int64
 14		want  int64
 15	}{
 16		{"one byte at the default price", 1, DefaultStoragePrice, 100},
 17		{"the measured reap", 17835, DefaultStoragePrice, 1783500},
 18		{"the measured compact", 830, DefaultStoragePrice, 83000},
 19		{"zero bytes", 0, DefaultStoragePrice, 0},
 20		{"negative bytes are not a credit", -100, DefaultStoragePrice, 0},
 21		{"a free chain refunds nothing", 1000, 0, 0},
 22		{"a ten-fold price rise", 1000, 1000, 1000000},
 23	}
 24	for _, tt := range tests {
 25		t.Run(tt.name, func(t *testing.T) {
 26			uassert.Equal(t, tt.want, Refund(tt.bytes, tt.price))
 27		})
 28	}
 29}
 30
 31func TestBreakEvenBytes(t *testing.T) {
 32	tests := []struct {
 33		name string
 34		fee  int64
 35		want int64
 36	}{
 37		// A 2.6M gas call at the floor costs 2,600 ugnot, so 26 bytes.
 38		{"the canonical 2.6M gas call", 2600, 26},
 39		{"rounds up, never down", 101, 2},
 40		{"exactly one byte", 100, 1},
 41		{"a fee below one byte still needs a byte", 1, 1},
 42		{"no fee, no threshold", 0, 0},
 43	}
 44	for _, tt := range tests {
 45		t.Run(tt.name, func(t *testing.T) {
 46			got := BreakEvenBytes(tt.fee, DefaultStoragePrice)
 47			uassert.Equal(t, tt.want, got)
 48			// The definition: this many bytes covers the fee, one fewer does not.
 49			if tt.want > 0 {
 50				uassert.True(t, Refund(got, DefaultStoragePrice) >= tt.fee)
 51				uassert.False(t, Refund(got-1, DefaultStoragePrice) >= tt.fee)
 52			}
 53		})
 54	}
 55	uassert.Equal(t, int64(0), BreakEvenBytes(1000, 0))
 56}
 57
 58func TestGasFee(t *testing.T) {
 59	// The floor mainnet has actually accepted: 1 ugnot per 1000 gas.
 60	uassert.Equal(t, int64(5000), FloorGasFee(5_000_000))
 61	uassert.Equal(t, int64(2500), FloorGasFee(2_500_000))
 62	// Rounds up, so a fee is never short.
 63	uassert.Equal(t, int64(1), FloorGasFee(1))
 64	uassert.Equal(t, int64(0), FloorGasFee(0))
 65	// The harness price used in the measurements, 1.2 ugnot per gas.
 66	uassert.Equal(t, int64(6_000_000), GasFee(5_000_000, 12, 10))
 67	uassert.Equal(t, int64(0), GasFee(5_000_000, 0, 10))
 68	uassert.Equal(t, int64(0), GasFee(5_000_000, 1, 0))
 69}
 70
 71func TestEvaluateReproducesTheMeasuredReap(t *testing.T) {
 72	// The measured run: 17,835 bytes freed by a call that used 4,120,876 gas,
 73	// so gas_wanted 5,000,000 at the floor. Net +1,778,500 ugnot.
 74	q := EvaluateAtFloor(17835, 5_000_000)
 75	uassert.Equal(t, int64(1783500), q.Refund)
 76	uassert.Equal(t, int64(5000), q.Fee)
 77	uassert.Equal(t, int64(1778500), q.Net)
 78	uassert.Equal(t, int64(50), q.BreakEven)
 79	uassert.True(t, q.Worth())
 80}
 81
 82func TestEvaluateReproducesTheMeasuredCompact(t *testing.T) {
 83	q := EvaluateAtFloor(830, 2_500_000)
 84	uassert.Equal(t, int64(83000), q.Refund)
 85	uassert.Equal(t, int64(2500), q.Fee)
 86	uassert.Equal(t, int64(80500), q.Net)
 87	uassert.True(t, q.Worth())
 88}
 89
 90func TestEvaluateAtTheHarnessPriceIsALoss(t *testing.T) {
 91	// The same reap priced at 1.2 ugnot/gas, 1200x the floor, loses money.
 92	// This is why the gas price cannot be baked into a contract.
 93	q := Evaluate(17835, DefaultStoragePrice, 5_000_000, 12, 10)
 94	uassert.Equal(t, int64(6_000_000), q.Fee)
 95	uassert.False(t, q.Worth())
 96	uassert.True(t, q.Net < 0)
 97}
 98
 99func TestQuoteString(t *testing.T) {
100	worth := EvaluateAtFloor(17835, 5_000_000)
101	uassert.Equal(t,
102		"17835 bytes, refunds 1.7835 GNOT against 0.005 GNOT of gas, break-even 50 bytes: worth 1.7785 GNOT",
103		worth.String())
104
105	loss := Evaluate(10, DefaultStoragePrice, 5_000_000, 12, 10)
106	uassert.Equal(t,
107		"10 bytes, refunds 0.001 GNOT against 6 GNOT of gas, break-even 60000 bytes: not worth it yet",
108		loss.String())
109}
110
111func TestFormatGNOT(t *testing.T) {
112	tests := []struct {
113		amount int64
114		want   string
115	}{
116		{0, "0 GNOT"},
117		{1, "0.000001 GNOT"},
118		{100, "0.0001 GNOT"},
119		{1_000_000, "1 GNOT"},
120		{1_500_000, "1.5 GNOT"},
121		{1_783_500, "1.7835 GNOT"},
122		{978_743_800, "978.7438 GNOT"},
123		{-2_100, "-0.0021 GNOT"},
124		{1_000_001, "1.000001 GNOT"},
125	}
126	for _, tt := range tests {
127		uassert.Equal(t, tt.want, FormatGNOT(tt.amount))
128	}
129}
130
131func TestEstimateBytes(t *testing.T) {
132	// Measured: a 1,024-byte payload occupied 1,898 bytes of realm state.
133	uassert.Equal(t, int64(1894), EstimateBytes(1024))
134	uassert.Equal(t, int64(0), EstimateBytes(0))
135	uassert.Equal(t, int64(0), EstimateBytes(-5))
136	// Monotonic, which is all a bounty estimate really needs.
137	uassert.True(t, EstimateBytes(2048) > EstimateBytes(1024))
138}
139
140// TestFormatGNOTIsTotal pins what v0 could not do. v0 negated in int64, so at
141// math.MinInt64 both halves kept a sign and it returned
142// "--9223372036854.-775808 GNOT". Delegating to kit/num is the fix; this
143// asserts the contract rather than the delegation.
144func TestFormatGNOTIsTotal(t *testing.T) {
145	const minInt64 = -9223372036854775808
146	uassert.Equal(t, "-9223372036854.775808 GNOT", FormatGNOT(minInt64))
147	uassert.Equal(t, "-1.5 GNOT", FormatGNOT(-1500000))
148	uassert.Equal(t, "-0.000001 GNOT", FormatGNOT(-1))
149	uassert.Equal(t, "1.5 GNOT", FormatGNOT(1500000))
150	uassert.Equal(t, "0 GNOT", FormatGNOT(0))
151}
152
153func TestEstimateNodes(t *testing.T) {
154	cases := []struct {
155		name  string
156		nodes int64
157		want  int64
158	}{
159		{"none", 0, 0},
160		{"negative is not an error", -5, 0},
161		// The mainnet measurement this constant comes from: compacting a
162		// drained 8-node board returned 6,848 bytes.
163		{"the mainnet sample", 8, 6848},
164		// And the local harness, which agreed to the byte.
165		{"the local harness sample", 31, 26536},
166	}
167	for _, tc := range cases {
168		uassert.Equal(t, tc.want, EstimateNodes(tc.nodes), tc.name)
169	}
170}
171
172// TestEstimateNodesBeatsEstimateBytesOnTheCaseThatBurnedUs pins the reason
173// EstimateNodes exists, not just what it computes.
174//
175// A realm advertised a bounty by running the payload length of five small
176// entries through EstimateBytes and got 481 bytes. Reaping and compacting them
177// actually returned 11,972. The payload path cannot see either the per-entry
178// floor or the container, and no existing test could catch that because they
179// all fed EstimateBytes the 1,024-byte payloads its ratio was measured on.
180func TestEstimateNodesBeatsEstimateBytesOnTheCaseThatBurnedUs(t *testing.T) {
181	const payload = 8 + 231 + 7 + 5 + 9 // the five note bodies, 260 bytes
182	const reallyFreed = 11972
183
184	guess := EstimateBytes(payload)
185	uassert.True(t, guess*20 < reallyFreed,
186		"EstimateBytes is still supposed to be the bad one here")
187
188	// The container half is the part that is countable, and counting it gets
189	// most of the way there on its own: 8 nodes were the larger share.
190	counted := EstimateNodes(8)
191	uassert.True(t, counted > guess*10,
192		"counting nodes should dominate guessing from payload")
193	uassert.True(t, counted <= reallyFreed,
194		"counting nodes must never over-advertise")
195}