@@ -1292,6 +1292,168 @@ func TestUpdaterIgnoreCommitments(t *testing.T) {
12921292 }
12931293}
12941294
1295+ func TestComputeResidualAfterDecay (t * testing.T ) {
1296+ t .Parallel ()
1297+
1298+ discardLogger := slog .New (slog .NewTextHandler (io .Discard , nil ))
1299+
1300+ u , err := updater .NewUpdater (
1301+ discardLogger ,
1302+ nil ,
1303+ nil ,
1304+ nil ,
1305+ nil ,
1306+ nil ,
1307+ )
1308+ if err != nil {
1309+ // The current NewUpdater only returns error on cache creation failure, unlikely here.
1310+ t .Fatalf ("Failed to create minimal updater instance for test: %v" , err )
1311+ }
1312+
1313+ tests := []struct {
1314+ name string
1315+ start uint64
1316+ end uint64
1317+ commit uint64
1318+ want * big.Int
1319+ }{
1320+ {
1321+ name : "Commit Before Start" ,
1322+ start : 1000 ,
1323+ end : 2000 ,
1324+ commit : 500 ,
1325+ want : updater .BigOneHundredPercent ,
1326+ },
1327+ {
1328+ name : "Commit At Start" ,
1329+ start : 1000 ,
1330+ end : 2000 ,
1331+ commit : 1000 ,
1332+ want : updater .BigOneHundredPercent ,
1333+ },
1334+ {
1335+ name : "Commit After End" ,
1336+ start : 1000 ,
1337+ end : 2000 ,
1338+ commit : 2500 ,
1339+ want : big .NewInt (0 ),
1340+ },
1341+ {
1342+ name : "Commit At End" ,
1343+ start : 1000 ,
1344+ end : 2000 ,
1345+ commit : 2000 ,
1346+ want : big .NewInt (0 ),
1347+ },
1348+ {
1349+ name : "Invalid Range: Start Equals End" ,
1350+ start : 1000 ,
1351+ end : 1000 ,
1352+ commit : 1000 ,
1353+ want : big .NewInt (0 ),
1354+ },
1355+ {
1356+ name : "Invalid Range: Start Greater Than End" ,
1357+ start : 2000 ,
1358+ end : 1000 ,
1359+ commit : 1500 ,
1360+ want : big .NewInt (0 ),
1361+ },
1362+ {
1363+ name : "Commit Exactly Midpoint" ,
1364+ start : 1000 ,
1365+ end : 2000 , // duration 1000
1366+ commit : 1500 , // 500 passed
1367+ want : big .NewInt (50 * updater .PRECISION ), // 1 - 500/1000 = 0.5 -> 50%
1368+ },
1369+ {
1370+ name : "Commit At 25% Time Passed" ,
1371+ start : 1000 ,
1372+ end : 2000 , // duration 1000
1373+ commit : 1250 , // 250 passed
1374+ want : big .NewInt (75 * updater .PRECISION ), // 1 - 250/1000 = 0.75 -> 75%
1375+ },
1376+ {
1377+ name : "Commit At 75% Time Passed" ,
1378+ start : 1000 ,
1379+ end : 2000 , // duration 1000
1380+ commit : 1750 , // 750 passed
1381+ want : big .NewInt (25 * updater .PRECISION ), // 1 - 750/1000 = 0.25 -> 25%
1382+ },
1383+ {
1384+ name : "Commit Very Close To Start" ,
1385+ start : 100000 ,
1386+ end : 200000 , // duration 100000
1387+ commit : 100001 , // 1 passed
1388+ // residual = 1 - 1/100000 = 0.99999
1389+ // percentage = 0.99999 * 100 = 99.999
1390+ // scaled = 99.999 * PRECISION
1391+ // Expected float: (1.0 - (1.0 / 100000.0)) * ONE_HUNDRED_PERCENT
1392+ // Expected float: 0.99999 * 100 * 1e16 = 99.999 * 1e16 = 999990000000000000
1393+ want : big .NewInt (999990000000000000 ),
1394+ },
1395+ {
1396+ name : "Commit Very Close To End" ,
1397+ start : 100000 ,
1398+ end : 200000 , // duration 100000
1399+ commit : 199000 , // 99000 passed
1400+ // residual = 1 - 99000/100000 = 1 - 0.99 = 0.01
1401+ // scaled = 0.01 * 100 * PRECISION = 1 * PRECISION
1402+ want : big .NewInt (1 * int64 (updater .PRECISION )),
1403+ },
1404+ {
1405+ name : "Zero Start Time" ,
1406+ start : 0 ,
1407+ end : 1000 , // duration 1000
1408+ commit : 500 , // 500 passed
1409+ want : big .NewInt (50 * updater .PRECISION ), // 1 - 500/1000 = 0.5 -> 50%
1410+ },
1411+ {
1412+ name : "Zero Start and Commit Time" ,
1413+ start : 0 ,
1414+ end : 1000 ,
1415+ commit : 0 ,
1416+ want : updater .BigOneHundredPercent ,
1417+ },
1418+ {
1419+ name : "Large Timestamps" ,
1420+ start : 1700000000000 , // example ms timestamps
1421+ end : 1700000012000 , // 12 second duration
1422+ commit : 1700000003000 , // 3 seconds passed
1423+ // residual = 1 - 3000/12000 = 1 - 0.25 = 0.75
1424+ // scaled = 0.75 * 100 * PRECISION = 75 * PRECISION
1425+ want : big .NewInt (75 * updater .PRECISION ),
1426+ },
1427+ {
1428+ name : "Minimal Valid Duration" ,
1429+ start : 1000 ,
1430+ end : 1001 , // duration 1
1431+ commit : 1000 ,
1432+ want : updater .BigOneHundredPercent ,
1433+ },
1434+ {
1435+ name : "Minimal Valid Duration, Commit slightly after start" ,
1436+ start : 1000 ,
1437+ end : 1002 , // duration 2
1438+ commit : 1001 , // passed 1
1439+ // residual = 1 - 1/2 = 0.5
1440+ want : big .NewInt (50 * updater .PRECISION ),
1441+ },
1442+ }
1443+
1444+ for _ , tc := range tests {
1445+ tc := tc
1446+ t .Run (tc .name , func (t * testing.T ) {
1447+ t .Parallel ()
1448+ got := u .ComputeResidualAfterDecay (tc .start , tc .end , tc .commit )
1449+
1450+ if got .Cmp (tc .want ) != 0 {
1451+ t .Errorf ("ComputeResidualAfterDecay(%d, %d, %d) = %v, want %v" , tc .start , tc .end , tc .commit , got , tc .want )
1452+ }
1453+ })
1454+ }
1455+ }
1456+
12951457type testSettlement struct {
12961458 commitmentIdx []byte
12971459 txHash string
0 commit comments