PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/moul/x/games/prorata/v0

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v0
Namespace
moul / x / games / prorata
Files
4 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/moul/x/games/prorata/v0
gno
0.9

Files (4)

  • README.mdmarkdown
  • gnomod.tomltoml
  • prorata.gnogno
  • prorata_test.gnogno
prorata_test.gnogno
1package prorata23import (4	"testing"56	"gno.land/p/nt/uassert/v0"7)89func sum(xs []int64) int64 {10	t := int64(0)11	for _, x := range xs {12		t += x13	}14	return t15}1617func TestSplitTable(t *testing.T) {18	cases := []struct {19		name    string20		amount  int6421		weights []int6422		want    []int6423	}{24		{"exact thirds", 99, []int64{1, 1, 1}, []int64{33, 33, 33}},25		{"one unit of dust, to the lowest index", 10, []int64{1, 1, 1}, []int64{4, 3, 3}},26		{"two units of dust", 11, []int64{1, 1, 1}, []int64{4, 4, 3}},27		{"uneven weights", 100, []int64{1, 2, 3}, []int64{17, 33, 50}},28		{"a single claimant takes it all", 7, []int64{5}, []int64{7}},29		{"zero weight is paid nothing", 10, []int64{0, 1, 1}, []int64{0, 5, 5}},30		{"zero weight is not paid dust either", 10, []int64{0, 1, 1, 1}, []int64{0, 4, 3, 3}},31		{"nothing to split", 0, []int64{3, 1}, []int64{0, 0}},32		{"amount smaller than the roster", 2, []int64{1, 1, 1, 1}, []int64{1, 1, 0, 0}},33		{"weight dominates", 1000, []int64{999, 1}, []int64{999, 1}},34	}35	for _, tc := range cases {36		got, err := Split(tc.amount, tc.weights)37		uassert.NoError(t, err, tc.name)38		uassert.Equal(t, len(tc.want), len(got), tc.name)39		for i := range tc.want {40			uassert.Equal(t, tc.want[i], got[i], tc.name)41		}42	}43}4445// TestSplitAlwaysSumsToTheAmount is the whole point: a split that is short by46// dust strands coins in the realm forever, and one that is over cannot be paid.47func TestSplitAlwaysSumsToTheAmount(t *testing.T) {48	weightsets := [][]int64{49		{1, 1, 1},50		{1, 2, 3, 4, 5, 6, 7},51		{7, 0, 1},52		{100, 1},53		{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},54		{1},55		{999983, 17, 5},56	}57	for _, ws := range weightsets {58		for amount := int64(0); amount < 60; amount++ {59			got, err := Split(amount, ws)60			uassert.NoError(t, err)61			uassert.Equal(t, amount, sum(got), "shares must sum to the amount")62		}63		for _, amount := range []int64{1000, 123457, 999999999} {64			got, err := Split(amount, ws)65			uassert.NoError(t, err)66			uassert.Equal(t, amount, sum(got))67		}68	}69}7071// TestLargestRemainderWins pins the allocation rule, so a payout cannot quietly72// change to "whoever the loop paid last".73func TestLargestRemainderWins(t *testing.T) {74	// total 10, amount 4: floors are 0,0,1,1 with remainders 4,8,2,6.75	got, err := Split(4, []int64{1, 2, 3, 4})76	uassert.NoError(t, err)77	uassert.Equal(t, int64(0), got[0], "smallest remainder, no extra unit")78	uassert.Equal(t, int64(1), got[1], "largest remainder, gets one")79	uassert.Equal(t, int64(1), got[2], "floor 1, remainder 2, gets none")80	uassert.Equal(t, int64(2), got[3], "second largest, gets the other")81	uassert.Equal(t, int64(4), sum(got))82}8384func TestSplitValidation(t *testing.T) {85	_, err := Split(-1, []int64{1})86	uassert.ErrorIs(t, err, ErrNegativeAmount)8788	_, err = Split(10, []int64{1, -1})89	uassert.ErrorIs(t, err, ErrNegativeWeight)9091	_, err = Split(10, nil)92	uassert.ErrorIs(t, err, ErrNoWeight, "an empty roster is the caller's problem, not dust")9394	_, err = Split(10, []int64{0, 0})95	uassert.ErrorIs(t, err, ErrNoWeight, "every weight zero is the same problem")96}9798// TestNoOverflowOnLargePots is the second failure mode: amount*weight wraps99// negative long before either factor is anywhere near the limit.100func TestNoOverflowOnLargePots(t *testing.T) {101	// A pot of 10^18 ugnot split across weights that would overflow if102	// multiplied together first.103	pot := int64(1000000000000000000)104	got, err := Split(pot, []int64{3000000000, 1000000000})105	uassert.NoError(t, err)106	uassert.Equal(t, pot, sum(got))107	uassert.Equal(t, int64(750000000000000000), got[0])108	uassert.Equal(t, int64(250000000000000000), got[1])109110	got, err = Split(maxInt64, []int64{1, 1})111	uassert.NoError(t, err)112	uassert.Equal(t, maxInt64, sum(got), "even the largest possible pot")113114	_, err = Total([]int64{maxInt64, 1})115	uassert.ErrorIs(t, err, ErrOverflow, "a wrapped total makes every share nonsense")116}117118func TestShare(t *testing.T) {119	got, err := Share(100, 1, 3)120	uassert.NoError(t, err)121	uassert.Equal(t, int64(33), got, "rounded down, the remainder is Split's job")122123	got, err = Share(1000000000000000000, 3000000000, 4000000000)124	uassert.NoError(t, err)125	uassert.Equal(t, int64(750000000000000000), got)126127	got, err = Share(100, 7, 3)128	uassert.NoError(t, err)129	uassert.Equal(t, int64(100), got, "a weight above the total is clamped, never over-paid")130131	_, err = Share(10, 1, 0)132	uassert.ErrorIs(t, err, ErrNoWeight)133	_, err = Share(-1, 1, 2)134	uassert.ErrorIs(t, err, ErrNegativeAmount)135	_, err = Share(10, -1, 2)136	uassert.ErrorIs(t, err, ErrNegativeWeight)137}138139func TestTotal(t *testing.T) {140	got, err := Total([]int64{1, 2, 3})141	uassert.NoError(t, err)142	uassert.Equal(t, int64(6), got)143144	got, err = Total(nil)145	uassert.NoError(t, err)146	uassert.Equal(t, int64(0), got, "empty sums to zero; Split is what refuses it")147}148

Functions

not supported for pure packages by the node (vm/qfuncs)

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.