Skip to content
This repository has been archived by the owner on Aug 22, 2023. It is now read-only.

migrate and enhance penalties subsuite from chain-validation. #108

Merged
merged 5 commits into from
Sep 3, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 58 additions & 25 deletions gen/builders/actors.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,19 @@ import (
"github.com/ipfs/go-cid"
)

type registeredActor struct {
handle AddressHandle
initial abi.TokenAmount
type Account struct {
Handle AddressHandle
Initial abi.TokenAmount
}

type Miner struct {
MinerActorAddr, OwnerAddr, WorkerAddr AddressHandle
}

// Actors is an object that manages actors in the test vector.
type Actors struct {
// registered stores registered actors and their initial balances.
registered []registeredActor
accounts []Account
miners []Miner

bc *BuilderCommon
st *StateTracker
Expand All @@ -38,30 +42,61 @@ func NewActors(bc *BuilderCommon, b *StateTracker) *Actors {
return &Actors{bc: bc, st: b}
}

// Count returns the number of actors registered during preconditions.
// Accounts returns all accounts that have been registered through
// Account() / AccountN().
//
// Miner owner and worker accounts, despite being accounts in the strict sense
// of the word, are not returned here. You can get them through Miners().
//
// Similarly, account actors registered through CreateActor() in a bare form are
// not returned here.
func (a *Actors) Accounts() []Account {
return a.accounts
}

// Miners returns all miners that have been registered through
// Miner() / MinerN(), along with their owner and worker account addresses.
//
// Miners registered through CreateActor() in a bare form are not returned here.
func (a *Actors) Miners() []Miner {
return a.miners
}
Comment on lines +45 to +63
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now you can get accounts and miners separately, each with their own struct containing the relevant data.


// Count returns the number of accounts and miners registered.
func (a *Actors) Count() int {
return len(a.registered)
return len(a.accounts) + len(a.miners)
}

// HandleFor gets the canonical handle for a registered address, which can
// appear at either ID or Robust position.
func (a *Actors) HandleFor(addr address.Address) AddressHandle {
for _, r := range a.registered {
if r.handle.ID == addr || r.handle.Robust == addr {
return r.handle
for _, r := range a.accounts {
if r.Handle.ID == addr || r.Handle.Robust == addr {
return r.Handle
}
}
for _, r := range a.miners {
if r.MinerActorAddr.ID == addr || r.MinerActorAddr.Robust == addr {
return r.MinerActorAddr
}
if r.OwnerAddr.ID == addr || r.OwnerAddr.Robust == addr {
return r.OwnerAddr
}
if r.WorkerAddr.ID == addr || r.WorkerAddr.Robust == addr {
return r.WorkerAddr
}
}
a.bc.Assert.FailNowf("asked for handle of unknown actor", "actor: %s", addr)
return AddressHandle{} // will never reach here.
}

// InitialBalance returns the initial balance of an actor that was registered
// during preconditions. It matches against both the ID and Robust
// InitialBalance returns the initial balance of an account actor that was
// registered during preconditions. It matches against both the ID and Robust
// addresses. It records an assertion failure if the actor is unknown.
func (a *Actors) InitialBalance(addr address.Address) abi.TokenAmount {
for _, r := range a.registered {
if r.handle.ID == addr || r.handle.Robust == addr {
return r.initial
for _, r := range a.accounts {
if r.Handle.ID == addr || r.Handle.Robust == addr {
return r.Initial
}
}
a.bc.Assert.FailNowf("asked for initial balance of unknown actor", "actor: %s", addr)
Expand All @@ -70,9 +105,9 @@ func (a *Actors) InitialBalance(addr address.Address) abi.TokenAmount {

// Handles returns the AddressHandles for all registered actors.
func (a *Actors) Handles() []AddressHandle {
ret := make([]AddressHandle, 0, len(a.registered))
for _, r := range a.registered {
ret = append(ret, r.handle)
ret := make([]AddressHandle, 0, len(a.accounts))
for _, r := range a.accounts {
ret = append(ret, r.Handle)
}
return ret
}
Expand Down Expand Up @@ -102,7 +137,7 @@ func (a *Actors) Account(typ address.Protocol, balance abi.TokenAmount) AddressH
actorState := &account.State{Address: addr}
handle := a.CreateActor(builtin.AccountActorCodeID, addr, balance, actorState)

a.registered = append(a.registered, registeredActor{handle, balance})
a.accounts = append(a.accounts, Account{handle, balance})
return handle
}

Expand All @@ -112,10 +147,6 @@ type MinerActorCfg struct {
OwnerBalance abi.TokenAmount
}

type Miner struct {
MinerActorAddr, OwnerAddr, WorkerAddr AddressHandle
}

// Miner creates an owner account, a worker account, and a miner actor with the
// supplied configuration.
func (a *Actors) Miner(cfg MinerActorCfg) Miner {
Expand Down Expand Up @@ -197,12 +228,13 @@ func (a *Actors) Miner(cfg MinerActorCfg) Miner {
panic(err)
}

a.registered = append(a.registered, registeredActor{handle, big.Zero()})
return Miner{
m := Miner{
MinerActorAddr: handle,
OwnerAddr: owner,
WorkerAddr: worker,
}
a.miners = append(a.miners, m)
return m
}

// MinerN creates many miners with the specified configuration, and places the
Expand Down Expand Up @@ -243,5 +275,6 @@ func (a *Actors) CreateActor(code cid.Cid, addr address.Address, balance abi.Tok
if err := a.st.StateTree.SetActor(addr, actr); err != nil {
log.Panicf("setting new actor for actor: %v", err)
}

return AddressHandle{id, addr}
}
22 changes: 10 additions & 12 deletions gen/builders/builder_tipset.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ import (
type TipsetVectorBuilder struct {
*BuilderCommon

// StagedMessages and tmpStateTracker are the staging area for messages.
StagedMessages *Messages
tmpStateTracker *StateTracker
// StagedMessages is a staging area for messages.
StagedMessages *Messages
// StateTracker is used for staging messages, and it's scrapped and replaced
// by a fork at the PreRoot when committing applies.
StateTracker *StateTracker
Comment on lines +40 to +44
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified the temporary state tracker construction here. We now just have one state tracker, and we replace it in CommitApplies by recovering the pre-state.


InitialEpoch abi.ChainEpoch
Tipsets *TipsetSeq
StateTracker *StateTracker
Rewards *Rewards

PreRoot cid.Cid
Expand Down Expand Up @@ -79,11 +80,6 @@ func TipsetVector(metadata *schema.Metadata, selector schema.Selector, mode Mode
return b.Tipsets.Messages()
},
stateTracker: func() *StateTracker {
// if we're in the preconditions stage, return the staging state tracker.
// else, return the definite stage tracker.
if b.Stage == StageApplies {
return b.tmpStateTracker
}
return b.StateTracker
},
actors: func() *Actors { return bc.Actors },
Expand Down Expand Up @@ -131,8 +127,7 @@ func (b *TipsetVectorBuilder) CommitPreconditions() {
// update the internal state.
// create a staging state tracker that will be used during applies.
// create the message staging area, linked to the temporary state tracker.
b.tmpStateTracker = b.StateTracker.Fork(preroot)
b.StagedMessages = NewMessages(b.BuilderCommon, b.tmpStateTracker)
b.StagedMessages = NewMessages(b.BuilderCommon, b.StateTracker)

b.Stage = StageApplies
b.Assert.enterStage(StageApplies)
Expand All @@ -153,6 +148,9 @@ func (b *TipsetVectorBuilder) CommitApplies() {
panic("called CommitApplies at the wrong time")
}

// discard the temporary state, and fork at the preroot.
b.StateTracker = b.StateTracker.Fork(b.PreRoot)

var (
ds = b.StateTracker.Stores.Datastore
bs = b.StateTracker.Stores.Blockstore
Expand All @@ -163,7 +161,7 @@ func (b *TipsetVectorBuilder) CommitApplies() {
// instantiate the reward tracker
// record a rewards observation at the initial epoch.
b.Rewards = NewRewards(b.BuilderCommon, b.StateTracker)
b.Rewards.RecordAt(b.InitialEpoch)
b.Rewards.RecordAt(0)

// Initialize Postconditions on the vector; set the preroot as the temporary
// postcondition root.
Expand Down
37 changes: 20 additions & 17 deletions gen/builders/gas.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,37 @@ const (
overuseDen = 10
)

// CalculateDeduction returns the balance that shall be deducted from the
// CalculateSenderDeduction returns the balance that shall be deducted from the
// sender's account as a result of applying this message.
func CalculateDeduction(am *ApplicableMessage) big.Int {
func CalculateSenderDeduction(am *ApplicableMessage) big.Int {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More explicit naming to reduce cognitive load.

if am.Result.GasUsed == 0 {
return big.Zero()
}

m := am.Message
minerReward := GetMinerReward(m.GasLimit, m.GasPremium) // goes to the miner
burn := CalculateBurn(m.GasLimit, am.Result.GasUsed) // vanishes
deducted := big.Add(minerReward, burn) // sum of gas accrued

var (
minerReward = GetMinerReward(am) // goes to the miner
burn = CalculateBurntGas(am) // vanishes
deducted = big.Add(minerReward, burn) // sum of gas accrued
)
if am.Result.ExitCode.IsSuccess() {
deducted = big.Add(deducted, m.Value) // message value
deducted = big.Add(deducted, am.Message.Value) // message value
}
return deducted
}

// GetMinerReward returns the amount that the miner gets to keep, aka. miner tip.
func GetMinerReward(gasLimit int64, gasPremium abi.TokenAmount) abi.TokenAmount {
return big.Mul(big.NewInt(gasLimit), gasPremium)
}

func GetMinerPenalty(gasLimit int64) big.Int {
return big.Mul(lotus.BaseFee, big.NewInt(gasLimit))
func GetMinerReward(am *ApplicableMessage) abi.TokenAmount {
gasLimit := big.NewInt(am.Message.GasLimit)
gasPremium := am.Message.GasPremium
return big.Mul(gasLimit, gasPremium)
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calculating the miner penalty is not as straightforward, and this function wasn't even used in chain-validation. Nuking it.


// CalculateBurn calcualtes the amount that will be burnt, a function of the
// CalculateBurntGas calculates the amount that will be burnt, a function of the
// gas limit and the gas actually used.
func CalculateBurn(gasLimit int64, gasUsed int64) big.Int {
func CalculateBurntGas(am *ApplicableMessage) big.Int {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More explicit naming. This calculates burnt gas. Miner penalties are also burnt, and I needed to disambiguate.

gasLimit := am.Message.GasLimit
gasUsed := am.Result.GasUsed

over := gasLimit - (overuseNum*gasUsed)/overuseDen
if over < 0 {
over = 0
Expand All @@ -52,7 +53,9 @@ func CalculateBurn(gasLimit int64, gasUsed int64) big.Int {

overestimateGas := big.NewInt(gasLimit - gasUsed)
overestimateGas = big.Mul(overestimateGas, big.NewInt(over))
overestimateGas = big.Div(overestimateGas, big.NewInt(gasUsed))
if gasUsed != 0 {
overestimateGas = big.Div(overestimateGas, big.NewInt(gasUsed))
}
Comment on lines +56 to +58
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoiding divisions by zero.


totalBurnGas := big.Add(overestimateGas, big.NewInt(gasUsed))
return big.Mul(lotus.BaseFee, totalBurnGas)
Expand Down
2 changes: 1 addition & 1 deletion gen/builders/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (m *Messages) ApplyOne(am *ApplicableMessage) {
}
// verify that preceding messages have been applied.
// this will abort if unsatisfied.
m.bc.Assert.Nil(other.Result, "preceding messages must have been applied when calling Apply*; index of first unapplied: %d", i)
m.bc.Assert.NotNil(other.Result, "preceding messages must have been applied when calling Apply*; index of first unapplied: %d", i)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a genuine bug.

}
m.bc.Assert.True(found, "ApplicableMessage not found")
m.st.ApplyMessage(am)
Expand Down
2 changes: 1 addition & 1 deletion gen/builders/predicates.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func BalanceUpdated(offset abi.TokenAmount) ActorPredicate {
// accumulate all balance deductions: ∑(burnt + premium + transferred value)
deducted := big.Zero()
for _, am := range amss {
d := CalculateDeduction(am)
d := CalculateSenderDeduction(am)
deducted = big.Add(deducted, d)
}

Expand Down
16 changes: 8 additions & 8 deletions gen/suites/nested/nested.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func nestedSends_OkBasic(v *MessageVectorBuilder) {

//td.AssertActor(stage.creator, big.Sub(big.Add(balanceBefore, amtSent), result.Result.Receipt.GasUsed.Big()), nonce+1)
v.Assert.NonceEq(stage.creator, nonce+1)
v.Assert.BalanceEq(stage.creator, big.Sub(big.Add(balanceBefore, amtSent), CalculateDeduction(result)))
v.Assert.BalanceEq(stage.creator, big.Sub(big.Add(balanceBefore, amtSent), CalculateSenderDeduction(result)))
}

func nestedSends_OkToNewActor(v *MessageVectorBuilder) {
Expand All @@ -53,7 +53,7 @@ func nestedSends_OkToNewActor(v *MessageVectorBuilder) {
result := stage.sendOk(newAddr, amtSent, builtin.MethodSend, nil, nonce)

v.Assert.BalanceEq(stage.msAddr, big.Sub(multisigBalance, amtSent))
v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateDeduction(result)))
v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateSenderDeduction(result)))
v.Assert.BalanceEq(newAddr, amtSent)
}

Expand All @@ -75,7 +75,7 @@ func nestedSends_OkToNewActorWithInvoke(v *MessageVectorBuilder) {
//assert.Equal(t, expected.Bytes(), result.Result.Receipt.ReturnValue)

v.Assert.BalanceEq(stage.msAddr, big.Sub(multisigBalance, amtSent))
v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateDeduction(result)))
v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateSenderDeduction(result)))
v.Assert.BalanceEq(newAddr, amtSent)
}

Expand All @@ -94,7 +94,7 @@ func nestedSends_OkRecursive(v *MessageVectorBuilder) {
result := stage.sendOk(stage.msAddr, big.Zero(), builtin.MethodsMultisig.AddSigner, &params, nonce)

v.Assert.BalanceEq(stage.msAddr, multisigBalance)
v.Assert.Equal(big.Sub(balanceBefore, CalculateDeduction(result)), v.StateTracker.Balance(stage.creator))
v.Assert.Equal(big.Sub(balanceBefore, CalculateSenderDeduction(result)), v.StateTracker.Balance(stage.creator))

var st multisig.State
v.StateTracker.ActorState(stage.msAddr, &st)
Expand Down Expand Up @@ -164,8 +164,8 @@ func nestedSends_FailInvalidMethodNumForActor(v *MessageVectorBuilder) {
amtSent := abi.NewTokenAmount(1)
result := stage.sendOk(stage.creator, amtSent, abi.MethodNum(99), nil, nonce)

v.Assert.BalanceEq(stage.msAddr, multisigBalance) // No change.
v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateDeduction(result))) // Pay gas, don't receive funds.
v.Assert.BalanceEq(stage.msAddr, multisigBalance) // No change.
v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateSenderDeduction(result))) // Pay gas, don't receive funds.
}

func nestedSends_FailMissingParams(v *MessageVectorBuilder) {
Expand All @@ -178,7 +178,7 @@ func nestedSends_FailMissingParams(v *MessageVectorBuilder) {
amtSent := abi.NewTokenAmount(1)
result := stage.sendOk(stage.msAddr, amtSent, builtin.MethodsMultisig.AddSigner, params, nonce)

v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateDeduction(result)))
v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateSenderDeduction(result)))
v.Assert.BalanceEq(stage.msAddr, multisigBalance) // No change.
v.Assert.Equal(1, len(stage.state().Signers)) // No new signers
}
Expand All @@ -199,7 +199,7 @@ func nestedSends_FailMismatchParams(v *MessageVectorBuilder) {
amtSent := abi.NewTokenAmount(1)
result := stage.sendOk(stage.msAddr, amtSent, builtin.MethodsMultisig.AddSigner, &params, nonce)

v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateDeduction(result)))
v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateSenderDeduction(result)))
v.Assert.BalanceEq(stage.msAddr, multisigBalance) // No change.
v.Assert.Equal(1, len(stage.state().Signers)) // No new signers
}
Expand Down
Loading