Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into pedro/enhance_tx_bu…
Browse files Browse the repository at this point in the history
…ilder
  • Loading branch information
otherview committed Oct 9, 2024
2 parents e27c00a + 48cead2 commit 4026717
Show file tree
Hide file tree
Showing 11 changed files with 329 additions and 61 deletions.
39 changes: 31 additions & 8 deletions .github/workflows/gosec.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
name: Gosec
on:
push:
branches:
- master
pull_request:
branches:
- master
schedule:
# # This is meant to run every day at 8am
- cron: '0 8 * * 1-5'

jobs:
tests:
gosec:
runs-on: ubuntu-latest
env:
GO111MODULE: on
outputs:
gosec-status: ${{ steps.gosec-run.outcome }}
steps:
- name: Checkout Source
uses: actions/checkout@v4
Expand All @@ -20,6 +19,30 @@ jobs:
go-version: '1.22'
cache: false
- name: Run Gosec
id: gosec-run
continue-on-error: true
uses: securego/gosec@master
with:
args: '-exclude=G104,G115,G304,G406,G507 -exclude-dir=builtin/gen ./...'
args: '-exclude=G104,G115,G304,G406,G507 -exclude-dir=builtin/gen ./...'

notify-slack:
name: Notify Slack
needs:
- gosec
if: always() && needs.gosec.outputs.gosec-status == 'failure'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Notify Slack
uses: slackapi/[email protected]
env:
SLACK_WEBHOOK_URL: ${{ secrets.GOSEC_SLACK_WEBHOOK }}
with:
payload: |
{
"commit-url": "${{ github.event.head_commit.url }}",
"branch": "${{ github.ref }}",
"repository": "${{ github.repository }}",
}
3 changes: 1 addition & 2 deletions .github/workflows/test-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ jobs:
retention-days: 7

run-tests:
# https://docs.aws.amazon.com/codebuild/latest/userguide/action-runner.html#sample-github-action-runners-create-project
runs-on: codebuild-ThorGHA-${{ github.run_id }}-${{ github.run_attempt }}-ubuntu-7.0-large
runs-on: ubuntu-latest
needs: build-docker-image
env:
THOR_IMAGE: vechain/thor:${{ github.sha }}
Expand Down
3 changes: 2 additions & 1 deletion api/doc/thor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1186,7 +1186,7 @@ components:
- $ref: '#/components/schemas/ClauseTracerOption'
example:
target: '0x010709463c1f0c9aa66a31182fb36d1977d99bfb6526bae0564a0eac4006c31a/0/0'
name: "prestate"
name: "call"
config: { }

PostDebugTracerCallRequest:
Expand All @@ -1207,6 +1207,7 @@ components:
gasPayer: "0xd3ae78222beadb038203be21ed5ce7c9b1bff602"
expiration: 1000
blockRef: "0x00000000851caf3c"
name: "call"

TxMeta:
title: TxMeta
Expand Down
16 changes: 9 additions & 7 deletions runtime/resolved_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ func (r *ResolvedTransaction) BuyGas(state *state.State, blockTime uint64) (
baseGasPrice *big.Int,
gasPrice *big.Int,
payer thor.Address,
prepaid *big.Int,
returnGas func(uint64) error,
err error,
) {
Expand All @@ -113,19 +114,20 @@ func (r *ResolvedTransaction) BuyGas(state *state.State, blockTime uint64) (
return returnedEnergy, nil
}

prepaid := new(big.Int).Mul(new(big.Int).SetUint64(r.tx.Gas()), gasPrice)
// prepaid is the max total of gas cost available to spend on this transaction
prepaid = new(big.Int).Mul(new(big.Int).SetUint64(r.tx.Gas()), gasPrice)
if r.Delegator != nil {
var sufficient bool
if sufficient, err = energy.Sub(*r.Delegator, prepaid); err != nil {
return
}
if sufficient {
return baseGasPrice, gasPrice, *r.Delegator, func(rgas uint64) error {
return baseGasPrice, gasPrice, *r.Delegator, prepaid, func(rgas uint64) error {
_, err := doReturnGas(rgas)
return err
}, nil
}
return nil, nil, thor.Address{}, nil, errors.New("insufficient energy")
return nil, nil, thor.Address{}, nil, nil, errors.New("insufficient energy")
}

commonTo := r.CommonTo()
Expand Down Expand Up @@ -164,7 +166,7 @@ func (r *ResolvedTransaction) BuyGas(state *state.State, blockTime uint64) (
return
}
if ok {
return baseGasPrice, gasPrice, sponsor, doReturnGasAndSetCredit, nil
return baseGasPrice, gasPrice, sponsor, prepaid, doReturnGasAndSetCredit, nil
}
}
// deduct from To
Expand All @@ -174,7 +176,7 @@ func (r *ResolvedTransaction) BuyGas(state *state.State, blockTime uint64) (
return
}
if sufficient {
return baseGasPrice, gasPrice, *commonTo, doReturnGasAndSetCredit, nil
return baseGasPrice, gasPrice, *commonTo, prepaid, doReturnGasAndSetCredit, nil
}
}
}
Expand All @@ -186,9 +188,9 @@ func (r *ResolvedTransaction) BuyGas(state *state.State, blockTime uint64) (
}

if sufficient {
return baseGasPrice, gasPrice, r.Origin, func(rgas uint64) error { _, err := doReturnGas(rgas); return err }, nil
return baseGasPrice, gasPrice, r.Origin, prepaid, func(rgas uint64) error { _, err := doReturnGas(rgas); return err }, nil
}
return nil, nil, thor.Address{}, nil, errors.New("insufficient energy")
return nil, nil, thor.Address{}, nil, nil, errors.New("insufficient energy")
}

// ToContext create a tx context object.
Expand Down
2 changes: 1 addition & 1 deletion runtime/resolved_tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func (tr *testResolvedTransaction) TestBuyGas() {
if err != nil {
tr.t.Fatal(err)
}
_, _, payer, returnGas, err := resolve.BuyGas(state, targetTime)
_, _, payer, _, returnGas, err := resolve.BuyGas(state, targetTime)
tr.assert.Nil(err)
returnGas(100)
return payer
Expand Down
2 changes: 1 addition & 1 deletion runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ func (rt *Runtime) PrepareTransaction(tx *tx.Transaction) (*TransactionExecutor,
return nil, err
}

baseGasPrice, gasPrice, payer, returnGas, err := resolvedTx.BuyGas(rt.state, rt.ctx.Time)
baseGasPrice, gasPrice, payer, _, returnGas, err := resolvedTx.BuyGas(rt.state, rt.ctx.Time)
if err != nil {
return nil, err
}
Expand Down
28 changes: 24 additions & 4 deletions txpool/tx_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ type txObject struct {
*tx.Transaction
resolved *runtime.ResolvedTransaction

timeAdded int64
executable bool
timeAdded int64
localSubmitted bool // tx is submitted locally on this node, or synced remotely from p2p.
payer *thor.Address // payer of the tx, either origin, delegator, or on-chain delegation payer
cost *big.Int // total tx cost the payer needs to pay before execution(gas price * gas)

executable bool // don't touch this value, will be updated by the pool
overallGasPrice *big.Int // don't touch this value, it's only be used in pool's housekeeping
localSubmitted bool // tx is submitted locally on this node, or synced remotely from p2p.
}

func resolveTx(tx *tx.Transaction, localSubmitted bool) (*txObject, error) {
Expand All @@ -51,6 +54,14 @@ func (o *txObject) Delegator() *thor.Address {
return o.resolved.Delegator
}

func (o *txObject) Cost() *big.Int {
return o.cost
}

func (o *txObject) Payer() *thor.Address {
return o.payer
}

func (o *txObject) Executable(chain *chain.Chain, state *state.State, headBlock *block.Header) (bool, error) {
switch {
case o.Gas() > headBlock.GasLimit():
Expand Down Expand Up @@ -86,9 +97,18 @@ func (o *txObject) Executable(chain *chain.Chain, state *state.State, headBlock
return false, nil
}

if _, _, _, _, err := o.resolved.BuyGas(state, headBlock.Timestamp()+thor.BlockInterval); err != nil {
checkpoint := state.NewCheckpoint()
defer state.RevertTo(checkpoint)

_, _, payer, prepaid, _, err := o.resolved.BuyGas(state, headBlock.Timestamp()+thor.BlockInterval)
if err != nil {
return false, err
}

if !o.executable {
o.payer = &payer
o.cost = prepaid
}
return true, nil
}

Expand Down
80 changes: 67 additions & 13 deletions txpool/tx_object_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,28 @@ package txpool

import (
"errors"
"math/big"
"sync"

"github.com/vechain/thor/v2/thor"
"github.com/vechain/thor/v2/tx"
)

// txObjectMap to maintain mapping of tx hash to tx object, and account quota.
// txObjectMap to maintain mapping of tx hash to tx object, account quota and pending cost.
type txObjectMap struct {
lock sync.RWMutex
mapByHash map[thor.Bytes32]*txObject
mapByID map[thor.Bytes32]*txObject
quota map[thor.Address]int
cost map[thor.Address]*big.Int
}

func newTxObjectMap() *txObjectMap {
return &txObjectMap{
mapByHash: make(map[thor.Bytes32]*txObject),
mapByID: make(map[thor.Bytes32]*txObject),
quota: make(map[thor.Address]int),
cost: make(map[thor.Address]*big.Int),
}
}

Expand All @@ -36,7 +39,7 @@ func (m *txObjectMap) ContainsHash(txHash thor.Bytes32) bool {
return found
}

func (m *txObjectMap) Add(txObj *txObject, limitPerAccount int) error {
func (m *txObjectMap) Add(txObj *txObject, limitPerAccount int, validatePayer func(payer thor.Address, needs *big.Int) error) error {
m.lock.Lock()
defer m.lock.Unlock()

Expand All @@ -49,22 +52,50 @@ func (m *txObjectMap) Add(txObj *txObject, limitPerAccount int) error {
return errors.New("account quota exceeded")
}

if d := txObj.Delegator(); d != nil {
if m.quota[*d] >= limitPerAccount {
delegator := txObj.Delegator()
if delegator != nil {
if m.quota[*delegator] >= limitPerAccount {
return errors.New("delegator quota exceeded")
}
m.quota[*d]++
}

var (
cost *big.Int
payer thor.Address
)

if txObj.Cost() != nil {
payer = *txObj.Payer()
pending := m.cost[payer]

if pending == nil {
cost = new(big.Int).Set(txObj.Cost())
} else {
cost = new(big.Int).Add(pending, txObj.Cost())
}

if err := validatePayer(payer, cost); err != nil {
return err
}
}

m.quota[txObj.Origin()]++
if delegator != nil {
m.quota[*delegator]++
}

if cost != nil {
m.cost[payer] = cost
}

m.mapByHash[hash] = txObj
m.mapByID[txObj.ID()] = txObj
return nil
}

func (m *txObjectMap) GetByID(id thor.Bytes32) *txObject {
m.lock.Lock()
defer m.lock.Unlock()
m.lock.RLock()
defer m.lock.RUnlock()
return m.mapByID[id]
}

Expand All @@ -79,11 +110,22 @@ func (m *txObjectMap) RemoveByHash(txHash thor.Bytes32) bool {
delete(m.quota, txObj.Origin())
}

if d := txObj.Delegator(); d != nil {
if m.quota[*d] > 1 {
m.quota[*d]--
if delegator := txObj.Delegator(); delegator != nil {
if m.quota[*delegator] > 1 {
m.quota[*delegator]--
} else {
delete(m.quota, *d)
delete(m.quota, *delegator)
}
}

// update the pending cost of payers
if payer := txObj.Payer(); payer != nil {
if pending := m.cost[*payer]; pending != nil {
if pending.Cmp(txObj.Cost()) <= 0 {
delete(m.cost, *payer)
} else {
m.cost[*payer] = new(big.Int).Sub(pending, txObj.Cost())
}
}
}

Expand All @@ -94,6 +136,17 @@ func (m *txObjectMap) RemoveByHash(txHash thor.Bytes32) bool {
return false
}

func (m *txObjectMap) UpdatePendingCost(txObj *txObject) {
m.lock.Lock()
defer m.lock.Unlock()

if pending := m.cost[*txObj.Payer()]; pending != nil {
m.cost[*txObj.Payer()] = new(big.Int).Add(pending, txObj.Cost())
} else {
m.cost[*txObj.Payer()] = new(big.Int).Set(txObj.Cost())
}
}

func (m *txObjectMap) ToTxObjects() []*txObject {
m.lock.RLock()
defer m.lock.RUnlock()
Expand Down Expand Up @@ -125,11 +178,12 @@ func (m *txObjectMap) Fill(txObjs []*txObject) {
}
// skip account limit check
m.quota[txObj.Origin()]++
if d := txObj.Delegator(); d != nil {
m.quota[*d]++
if delegator := txObj.Delegator(); delegator != nil {
m.quota[*delegator]++
}
m.mapByHash[txObj.Hash()] = txObj
m.mapByID[txObj.ID()] = txObj
// skip cost check and accumulation
}
}

Expand Down
Loading

0 comments on commit 4026717

Please sign in to comment.