Commit c91894e8 authored by Luke Champine's avatar Luke Champine

Merge branch '3488-overspend-allowance' into 'master'

Resolve "Fees exceed the value of allowance"

Closes #3488

See merge request !3581
parents 6ee1378d b831cfb3
Pipeline #57497738 failed with stages
in 27 minutes and 47 seconds
......@@ -219,6 +219,43 @@ func TestIntegrationFormContract(t *testing.T) {
}
}
// TestFormContractSmallAllowance tests to make sure that a contract doesn't
// form when there are insufficient funds in the allowance
func TestFormContractSmallAllowance(t *testing.T) {
if testing.Short() {
t.SkipNow()
}
t.Parallel()
h, c, _, err := newTestingTrio(t.Name())
if err != nil {
t.Fatal(err)
}
defer h.Close()
defer c.Close()
// get the host's entry from the db
hostEntry, ok := c.hdb.Host(h.PublicKey())
if !ok {
t.Fatal("no entry for host in db")
}
// set an allowance but don't use SetAllowance to avoid automatic contract
// formation. Setting funds to 1SC to mimic bug report found in production.
// Using production number of hosts as well
c.mu.Lock()
c.allowance = modules.DefaultAllowance
c.allowance.Funds = types.SiacoinPrecision.Mul64(1)
c.allowance.Hosts = uint64(50)
initialContractFunds := c.allowance.Funds.Div64(c.allowance.Hosts).Div64(3)
c.mu.Unlock()
// try to form a contract with the host
_, _, err = c.managedNewContract(hostEntry, initialContractFunds, c.blockHeight+100)
if err == nil {
t.Fatal("Expected underflow error for insufficient funds")
}
}
// TestIntegrationReviseContract tests that the contractor can revise a
// contract previously formed with a host.
func TestIntegrationReviseContract(t *testing.T) {
......
......@@ -1347,6 +1347,7 @@ func TestRenterAddNodes(t *testing.T) {
// Specify subtests to run
subTests := []test{
{"TestRedundancyReporting", testRedundancyReporting}, // Put first because it pulls the original tg renter
{"TestOverspendAllowance", testOverspendAllowance},
{"TestRenterCancelAllowance", testRenterCancelAllowance},
{"TestRenewFailing", testRenewFailing}, // Put last because it impacts a host
}
......@@ -1793,6 +1794,91 @@ func testRenterCancelAllowance(t *testing.T, tg *siatest.TestGroup) {
}
}
// testOverspendAllowance tests that setting a small allowance and trying to
// form contracts will not result in overspending the allowance
func testOverspendAllowance(t *testing.T, tg *siatest.TestGroup) {
renterParams := node.Renter(filepath.Join(renterTestDir(t.Name()), "renter"))
renterParams.SkipSetAllowance = true
nodes, err := tg.AddNodes(renterParams)
if err != nil {
t.Fatal(err)
}
renter := nodes[0]
// Set the allowance with only 4SC
allowance := siatest.DefaultAllowance
allowance.Funds = types.SiacoinPrecision.Mul64(4)
if err := renter.RenterPostAllowance(allowance); err != nil {
t.Fatal(err)
}
// Mine a block to start the threadedContractMaintenance.
if err := tg.Miners()[0].MineBlock(); err != nil {
t.Fatal(err)
}
// Try and form multiple sets of contracts by canceling any contracts that
// form
count := 0
times := 0
err = build.Retry(200, 100*time.Millisecond, func() error {
// Mine Blocks every 5 iterations to ensure that contracts are
// continually trying to be created
count++
if count%5 == 0 {
if err := tg.Miners()[0].MineBlock(); err != nil {
return err
}
}
// Get contracts
rc, err := renter.RenterContractsGet()
if err != nil {
return err
}
// Check if any contracts have formed
if len(rc.ActiveContracts) == 0 {
times++
// Return if there have been 20 consecutive iterations with no new
// contracts
if times > 20 {
return nil
}
return errors.New("no contracts to cancel")
}
times = 0
// Cancel any active contracts
for _, contract := range rc.ActiveContracts {
err = renter.RenterContractCancelPost(contract.ID)
if err != nil {
return err
}
}
return errors.New("contracts still forming")
})
if err != nil {
t.Fatal(err)
}
// Confirm that contracts were formed
rc, err := renter.RenterInactiveContractsGet()
if err != nil {
t.Fatal(err)
}
if len(rc.ActiveContracts) == 0 && len(rc.InactiveContracts) == 0 {
t.Fatal("No Contracts formed")
}
// Confirm that the total allocated did not exceed the allowance funds
rg, err := renter.RenterGet()
if err != nil {
t.Fatal(err)
}
funds := rg.Settings.Allowance.Funds
allocated := rg.FinancialMetrics.TotalAllocated
if funds.Cmp(allocated) < 0 {
t.Fatalf("%v allocated exceeds allowance of %v", allocated, funds)
}
}
// TestRenterContracts tests the formation of the contracts, the contracts
// endpoint, and canceling a contract
func TestRenterContracts(t *testing.T) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment