Use Add instead of Push to correctly order timed txs in event heap

This commit is contained in:
Aaron Buchwald 2020-06-09 13:51:11 -04:00
parent 11ca40c9bf
commit e15c1bad8c
5 changed files with 78 additions and 12 deletions

View File

@ -1275,7 +1275,7 @@ func (service *Service) IssueTx(_ *http.Request, args *IssueTxArgs, response *Is
if err := tx.initialize(service.vm); err != nil { if err := tx.initialize(service.vm); err != nil {
return fmt.Errorf("error initializing tx: %s", err) return fmt.Errorf("error initializing tx: %s", err)
} }
service.vm.unissuedEvents.Push(tx) service.vm.unissuedEvents.Add(tx)
response.TxID = tx.ID() response.TxID = tx.ID()
case DecisionTx: case DecisionTx:
if err := tx.initialize(service.vm); err != nil { if err := tx.initialize(service.vm); err != nil {

View File

@ -4,7 +4,6 @@
package platformvm package platformvm
import ( import (
"container/heap"
"errors" "errors"
"net/http" "net/http"
@ -174,8 +173,8 @@ func (*StaticService) BuildGenesis(_ *http.Request, args *BuildGenesisArgs, repl
return errAccountHasNoValue return errAccountHasNoValue
} }
accounts = append(accounts, newAccount( accounts = append(accounts, newAccount(
account.Address, // ID account.Address, // ID
0, // nonce 0, // nonce
uint64(account.Balance), // balance uint64(account.Balance), // balance
)) ))
} }
@ -210,7 +209,7 @@ func (*StaticService) BuildGenesis(_ *http.Request, args *BuildGenesisArgs, repl
return err return err
} }
heap.Push(validators, tx) validators.Add(tx)
} }
// Specify the chains that exist at genesis. // Specify the chains that exist at genesis.

View File

@ -111,3 +111,72 @@ func TestBuildGenesisInvalidEndtime(t *testing.T) {
t.Fatalf("Should have errored due to an invalid end time") t.Fatalf("Should have errored due to an invalid end time")
} }
} }
func TestBuildGenesisReturnsSortedValidators(t *testing.T) {
id := ids.NewShortID([20]byte{1})
account := APIAccount{
Address: id,
Balance: 123456789,
}
weight := json.Uint64(987654321)
validator1 := APIDefaultSubnetValidator{
APIValidator: APIValidator{
StartTime: 0,
EndTime: 20,
Weight: &weight,
ID: id,
},
Destination: id,
}
validator2 := APIDefaultSubnetValidator{
APIValidator: APIValidator{
StartTime: 3,
EndTime: 15,
Weight: &weight,
ID: id,
},
Destination: id,
}
validator3 := APIDefaultSubnetValidator{
APIValidator: APIValidator{
StartTime: 1,
EndTime: 10,
Weight: &weight,
ID: id,
},
Destination: id,
}
args := BuildGenesisArgs{
Accounts: []APIAccount{
account,
},
Validators: []APIDefaultSubnetValidator{
validator1,
validator2,
validator3,
},
Time: 5,
}
reply := BuildGenesisReply{}
ss := StaticService{}
if err := ss.BuildGenesis(nil, &args, &reply); err != nil {
t.Fatalf("BuildGenesis should not have errored")
}
genesis := &Genesis{}
Codec.Unmarshal(reply.Bytes.Bytes, genesis)
validators := genesis.Validators
currentValidator := validators.Remove()
for validators.Len() > 0 {
nextValidator := validators.Remove()
if currentValidator.EndTime().Unix() > nextValidator.EndTime().Unix() {
t.Fatalf("Validators returned by genesis should be a min heap sorted by end time")
}
currentValidator = nextValidator
}
}

View File

@ -4,7 +4,6 @@
package platformvm package platformvm
import ( import (
"container/heap"
"errors" "errors"
"fmt" "fmt"
"time" "time"
@ -698,7 +697,7 @@ func (vm *VM) resetTimer() {
vm.SnowmanVM.NotifyBlockReady() // Should issue a ProposeAddValidator vm.SnowmanVM.NotifyBlockReady() // Should issue a ProposeAddValidator
return return
} }
// If the tx doesn't meet the syncrony bound, drop it // If the tx doesn't meet the synchrony bound, drop it
vm.unissuedEvents.Remove() vm.unissuedEvents.Remove()
vm.Ctx.Log.Debug("dropping tx to add validator because its start time has passed") vm.Ctx.Log.Debug("dropping tx to add validator because its start time has passed")
} }
@ -780,8 +779,8 @@ func (vm *VM) calculateValidators(db database.Database, timestamp time.Time, sub
if timestamp.Before(nextTx.StartTime()) { if timestamp.Before(nextTx.StartTime()) {
break break
} }
heap.Push(current, nextTx) current.Add(nextTx)
heap.Pop(pending) pending.Remove()
started.Add(nextTx.Vdr().ID()) started.Add(nextTx.Vdr().ID())
} }
return current, pending, started, stopped, nil return current, pending, started, stopped, nil

View File

@ -5,7 +5,6 @@ package platformvm
import ( import (
"bytes" "bytes"
"container/heap"
"errors" "errors"
"testing" "testing"
"time" "time"
@ -226,7 +225,7 @@ func GenesisCurrentValidators() *EventHeap {
testNetworkID, // network ID testNetworkID, // network ID
key, // key paying tx fee and stake key, // key paying tx fee and stake
) )
heap.Push(validators, validator) validators.Add(validator)
} }
return validators return validators
} }
@ -1011,7 +1010,7 @@ func TestCreateSubnet(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
vm.unissuedEvents.Push(addValidatorTx) vm.unissuedEvents.Add(addValidatorTx)
blk, err = vm.BuildBlock() // should add validator to the new subnet blk, err = vm.BuildBlock() // should add validator to the new subnet
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)