Skip to content

Commit

Permalink
Merge pull request #200 from OffchainLabs/fix-keepalive
Browse files Browse the repository at this point in the history
Fix activation keepalive cost
  • Loading branch information
rachel-bousfield authored Jan 23, 2024
2 parents 56f978e + c817c85 commit abce7c5
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 39 deletions.
4 changes: 2 additions & 2 deletions arbos/programs/data_pricer.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ func (p *DataPricer) UpdateModel(tempBytes uint32, time uint64) (*big.Int, error
return nil, err
}

timeDelta := arbmath.SaturatingUUCast[uint32](time - lastUpdateTime)
credit := arbmath.SaturatingUMul(bytesPerSecond, timeDelta)
passed := arbmath.SaturatingUUCast[uint32](time - lastUpdateTime)
credit := arbmath.SaturatingUMul(bytesPerSecond, passed)
demand = arbmath.SaturatingUSub(demand, credit)
demand = arbmath.SaturatingUAdd(demand, tempBytes)

Expand Down
41 changes: 21 additions & 20 deletions arbos/programs/programs.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ type Programs struct {
}

type Program struct {
version uint16
initGas uint24
asmEstimate uint24 // Unit is a kb (predicted canonically)
footprint uint16
activatedAt uint64 // Last activation timestamp
secondsLeft uint64 // Not stored in state
version uint16
initGas uint24
asmEstimateKb uint24 // Predicted size of the asm
footprint uint16
activatedAt uint64 // Last activation timestamp
secondsLeft uint64 // Not stored in state
}

type uint24 = arbmath.Uint24
Expand Down Expand Up @@ -251,7 +251,7 @@ func (p Programs) ActivateProgram(evm *vm.EVM, address common.Address, debugMode
return 0, codeHash, common.Hash{}, nil, true, err
}

estimateKb, err := arbmath.IntToUint24((info.asmEstimate + 1023) / 1024) // stored in kilobytes
estimateKb, err := arbmath.IntToUint24(arbmath.DivCeil(info.asmEstimate, 1024)) // stored in kilobytes
if err != nil {
return 0, codeHash, common.Hash{}, nil, true, err
}
Expand All @@ -266,11 +266,11 @@ func (p Programs) ActivateProgram(evm *vm.EVM, address common.Address, debugMode
}

programData := Program{
version: stylusVersion,
initGas: initGas24,
asmEstimate: estimateKb,
footprint: info.footprint,
activatedAt: time,
version: stylusVersion,
initGas: initGas24,
asmEstimateKb: estimateKb,
footprint: info.footprint,
activatedAt: time,
}
return stylusVersion, codeHash, info.moduleHash, dataFee, false, p.setProgram(codeHash, programData)
}
Expand Down Expand Up @@ -367,11 +367,11 @@ func (p Programs) getProgram(codeHash common.Hash, time uint64) (Program, error)
return Program{}, err
}
program := Program{
version: arbmath.BytesToUint16(data[:2]),
initGas: arbmath.BytesToUint24(data[2:5]),
asmEstimate: arbmath.BytesToUint24(data[5:8]),
footprint: arbmath.BytesToUint16(data[8:10]),
activatedAt: arbmath.BytesToUint(data[10:18]),
version: arbmath.BytesToUint16(data[:2]),
initGas: arbmath.BytesToUint24(data[2:5]),
asmEstimateKb: arbmath.BytesToUint24(data[5:8]),
footprint: arbmath.BytesToUint16(data[8:10]),
activatedAt: arbmath.BytesToUint(data[10:18]),
}
if program.version == 0 {
return program, ProgramNotActivatedError()
Expand Down Expand Up @@ -404,7 +404,7 @@ func (p Programs) setProgram(codehash common.Hash, program Program) error {
data := common.Hash{}
copy(data[0:], arbmath.Uint16ToBytes(program.version))
copy(data[2:], arbmath.Uint24ToBytes(program.initGas))
copy(data[5:], arbmath.Uint24ToBytes(program.asmEstimate))
copy(data[5:], arbmath.Uint24ToBytes(program.asmEstimateKb))
copy(data[8:], arbmath.Uint16ToBytes(program.footprint))
copy(data[10:], arbmath.UintToBytes(program.activatedAt))
return p.programs.Set(codehash, data)
Expand Down Expand Up @@ -447,12 +447,13 @@ func (p Programs) ProgramKeepalive(codeHash common.Hash, time uint64) (*big.Int,
return nil, ProgramNeedsUpgradeError(program.version, stylusVersion)
}

cost, err := p.dataPricer.UpdateModel(program.asmEstimate.ToUint32(), time)
bytes := arbmath.SaturatingUMul(program.asmEstimateKb.ToUint32(), 1024)
dataFee, err := p.dataPricer.UpdateModel(bytes, time)
if err != nil {
return nil, err
}
program.activatedAt = time
return cost, p.setProgram(codeHash, program)
return dataFee, p.setProgram(codeHash, program)

}

Expand Down
2 changes: 1 addition & 1 deletion contracts
38 changes: 22 additions & 16 deletions precompiles/ArbWasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import (
type ArbWasm struct {
Address addr // 0x71

ProgramActivated func(ctx, mech, hash, hash, addr, uint16) error
ProgramActivatedGasCost func(hash, hash, addr, uint16) (uint64, error)
ProgramActivated func(ctx, mech, hash, hash, addr, huge, uint16) error
ProgramActivatedGasCost func(hash, hash, addr, huge, uint16) (uint64, error)
ProgramLifetimeExtended func(ctx, mech, hash, huge) error
ProgramLifetimeExtendedGasCost func(hash, huge) (uint64, error)

ProgramNotActivatedError func() error
ProgramNeedsUpgradeError func(version, stylusVersion uint16) error
ProgramExpiredError func(age uint64) error
Expand All @@ -22,24 +25,36 @@ type ArbWasm struct {
}

// Compile a wasm program with the latest instrumentation
func (con ArbWasm) ActivateProgram(c ctx, evm mech, value huge, program addr) (uint16, error) {
func (con ArbWasm) ActivateProgram(c ctx, evm mech, value huge, program addr) (uint16, huge, error) {
debug := evm.ChainConfig().DebugMode()

// charge a fixed cost up front to begin activation
if err := c.Burn(1659168); err != nil {
return 0, err
return 0, nil, err
}
version, codeHash, moduleHash, dataFee, takeAllGas, err := c.State.Programs().ActivateProgram(evm, program, debug)
if takeAllGas {
_ = c.BurnOut()
}
if err != nil {
return version, err
return version, dataFee, err
}
if err := con.payActivationDataFee(c, evm, value, dataFee); err != nil {
return version, err
return version, dataFee, err
}
return version, con.ProgramActivated(c, evm, codeHash, moduleHash, program, version)
return version, dataFee, con.ProgramActivated(c, evm, codeHash, moduleHash, program, dataFee, version)
}

// Extends a program's expiration date (reverts if too soon)
func (con ArbWasm) CodehashKeepalive(c ctx, evm mech, value huge, codehash bytes32) error {
dataFee, err := c.State.Programs().ProgramKeepalive(codehash, evm.Context.Time)
if err != nil {
return err
}
if err := con.payActivationDataFee(c, evm, value, dataFee); err != nil {
return err
}
return con.ProgramLifetimeExtended(c, evm, codehash, dataFee)
}

// Pays the data component of activation costs
Expand Down Expand Up @@ -103,15 +118,6 @@ func (con ArbWasm) CodehashVersion(c ctx, evm mech, codehash bytes32) (uint16, e
return c.State.Programs().CodehashVersion(codehash, evm.Context.Time)
}

// Extends a program's expiration date (reverts if too soon)
func (con ArbWasm) CodehashKeepalive(c ctx, evm mech, value huge, codehash bytes32) error {
dataFee, err := c.State.Programs().ProgramKeepalive(codehash, evm.Context.Time)
if err != nil {
return err
}
return con.payActivationDataFee(c, evm, value, dataFee)
}

// Gets the stylus version that program at addr was most recently compiled with
func (con ArbWasm) ProgramVersion(c ctx, evm mech, program addr) (uint16, error) {
codehash, err := c.GetCodeHash(program)
Expand Down
8 changes: 8 additions & 0 deletions util/arbmath/math.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,14 @@ func SaturatingNeg[T Signed](value T) T {
return -value
}

// Integer division but rounding up
func DivCeil[T Unsigned](value, divisor T) T {
if value%divisor == 0 {
return value / divisor
}
return value/divisor + 1
}

// ApproxExpBasisPoints return the Maclaurin series approximation of e^x, where x is denominated in basis points.
// The quartic polynomial will underestimate e^x by about 5% as x approaches 20000 bips.
func ApproxExpBasisPoints(value Bips, degree uint64) Bips {
Expand Down

0 comments on commit abce7c5

Please sign in to comment.