From 515c03daba411361518b168f63774878b6893c18 Mon Sep 17 00:00:00 2001 From: otherview Date: Wed, 28 Aug 2024 15:51:33 +0100 Subject: [PATCH 1/2] Adding transaction_call endpoint --- api/api.go | 2 +- api/transactions/transactions.go | 103 ++++++++++++++++-- api/transactions/transactions_test.go | 119 ++++++++++++++++++++- api/transactions/types.go | 144 ++++++++++++++++++++++++-- runtime/resolved_tx.go | 36 +++++++ runtime/runtime.go | 128 +++++++++++++++++++++++ 6 files changed, 515 insertions(+), 17 deletions(-) diff --git a/api/api.go b/api/api.go index 0ac399295..b666e89ad 100644 --- a/api/api.go +++ b/api/api.go @@ -81,7 +81,7 @@ func New( } blocks.New(repo, bft). Mount(router, "/blocks") - transactions.New(repo, txPool). + transactions.New(repo, stater, txPool, bft). Mount(router, "/transactions") debug.New(repo, stater, forkConfig, callGasLimit, allowCustomTracer, bft, allowedTracers). Mount(router, "/debug") diff --git a/api/transactions/transactions.go b/api/transactions/transactions.go index 85404cf21..322641094 100644 --- a/api/transactions/transactions.go +++ b/api/transactions/transactions.go @@ -6,6 +6,7 @@ package transactions import ( + "fmt" "net/http" "github.com/ethereum/go-ethereum/common/hexutil" @@ -13,20 +14,31 @@ import ( "github.com/gorilla/mux" "github.com/pkg/errors" "github.com/vechain/thor/v2/api/utils" + "github.com/vechain/thor/v2/bft" + "github.com/vechain/thor/v2/block" "github.com/vechain/thor/v2/chain" + "github.com/vechain/thor/v2/runtime" + "github.com/vechain/thor/v2/state" "github.com/vechain/thor/v2/thor" "github.com/vechain/thor/v2/txpool" + "github.com/vechain/thor/v2/xenv" ) +const maxTxSize = 64 * 1024 + type Transactions struct { - repo *chain.Repository - pool *txpool.TxPool + repo *chain.Repository + pool *txpool.TxPool + stater *state.Stater + bft bft.Finalizer } -func New(repo *chain.Repository, pool *txpool.TxPool) *Transactions { +func New(repo *chain.Repository, stater *state.Stater, pool *txpool.TxPool, bft bft.Finalizer) *Transactions { return &Transactions{ - repo, - pool, + repo: repo, + stater: stater, + pool: pool, + bft: bft, } } @@ -76,7 +88,7 @@ func (t *Transactions) getTransactionByID(txID thor.Bytes32, head thor.Bytes32, if t.repo.IsNotFound(err) { if allowPending { if pending := t.pool.Get(txID); pending != nil { - return convertTransaction(pending, nil), nil + return ConvertTransaction(pending, nil), nil } } return nil, nil @@ -88,7 +100,7 @@ func (t *Transactions) getTransactionByID(txID thor.Bytes32, head thor.Bytes32, if err != nil { return nil, err } - return convertTransaction(tx, summary.Header), nil + return ConvertTransaction(tx, summary.Header), nil } // GetTransactionReceiptByID get tx's receipt @@ -114,6 +126,7 @@ func (t *Transactions) getTransactionReceiptByID(txID thor.Bytes32, head thor.By return convertReceipt(receipt, summary.Header, tx) } + func (t *Transactions) handleSendTransaction(w http.ResponseWriter, req *http.Request) error { var rawTx *RawTx if err := utils.ParseJSON(req.Body, &rawTx); err != nil { @@ -214,6 +227,78 @@ func (t *Transactions) parseHead(head string) (thor.Bytes32, error) { return h, nil } +func (t *Transactions) txCall( + txCallMsg *Transaction, + header *block.Header, + st *state.State, +) (*CallReceipt, error) { + callAddr := txCallMsg.Origin + if callAddr.String() == (thor.Address{}).String() { + return nil, fmt.Errorf("no Origin address specified") + } + + // todo handle the txCallMsg.Delegator + txCallData, err := convertToTxTransaction(txCallMsg) + if err != nil { + return nil, fmt.Errorf("unable to convert transaction: %w", err) + } + + // validation from the mempool + // TODO add more validations that are mandatory + switch { + case txCallMsg.ChainTag != t.repo.ChainTag(): + return nil, fmt.Errorf("chain tag mismatch") + case txCallMsg.Size > maxTxSize: + return nil, fmt.Errorf("size too large") + } + if err = txCallData.TestFeatures(header.TxsFeatures()); err != nil { + return nil, err + } + + signer, _ := header.Signer() + rt := runtime.New(t.repo.NewChain(header.ParentID()), st, + &xenv.BlockContext{ + Beneficiary: header.Beneficiary(), + Signer: signer, + Number: header.Number(), + Time: header.Timestamp(), + GasLimit: header.GasLimit(), + TotalScore: header.TotalScore(), + }, + thor.NoFork) + + receipt, err := rt.CallTransaction(txCallData, &callAddr, nil) // TODO hook delegator + if err != nil { + // TODO add some metric here + return convertErrorCallReceipt(err, txCallMsg, &callAddr) + } + + return convertCallReceipt(receipt, txCallMsg, &callAddr) +} + +func (t *Transactions) handleCallTransaction(w http.ResponseWriter, req *http.Request) error { + txCallMsg := &Transaction{} + if err := utils.ParseJSON(req.Body, &txCallMsg); err != nil { + return utils.BadRequest(errors.WithMessage(err, "body")) + } + revision, err := utils.ParseRevision(req.URL.Query().Get("revision"), true) + if err != nil { + return utils.BadRequest(errors.WithMessage(err, "revision")) + } + summary, st, err := utils.GetSummaryAndState(revision, t.repo, t.bft, t.stater) + if err != nil { + if t.repo.IsNotFound(err) { + return utils.BadRequest(errors.WithMessage(err, "revision")) + } + return err + } + + results, err := t.txCall(txCallMsg, summary.Header, st) + if err != nil { + return err + } + return utils.WriteJSON(w, results) +} func (t *Transactions) Mount(root *mux.Router, pathPrefix string) { sub := root.PathPrefix(pathPrefix).Subrouter() @@ -229,4 +314,8 @@ func (t *Transactions) Mount(root *mux.Router, pathPrefix string) { Methods(http.MethodGet). Name("transactions_get_receipt"). HandlerFunc(utils.WrapHandlerFunc(t.handleGetTransactionReceiptByID)) + sub.Path("/call"). + Methods(http.MethodPost). + Name("transactions_call_tx"). + HandlerFunc(utils.WrapHandlerFunc(t.handleCallTransaction)) } diff --git a/api/transactions/transactions_test.go b/api/transactions/transactions_test.go index 52b127a56..94a908bd7 100644 --- a/api/transactions/transactions_test.go +++ b/api/transactions/transactions_test.go @@ -24,6 +24,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/vechain/thor/v2/api/transactions" "github.com/vechain/thor/v2/chain" + "github.com/vechain/thor/v2/cmd/thor/solo" "github.com/vechain/thor/v2/genesis" "github.com/vechain/thor/v2/muxdb" "github.com/vechain/thor/v2/packer" @@ -75,6 +76,14 @@ func TestTransaction(t *testing.T) { } { t.Run(name, tt) } + + // Call transaction + for name, tt := range map[string]func(*testing.T){ + "callTx": callTx, + "invalidCallTx": invalidCallTx, + } { + t.Run(name, tt) + } } func getTx(t *testing.T) { @@ -260,6 +269,114 @@ func handleGetTransactionReceiptByIDWithNonExistingHead(t *testing.T) { assert.Equal(t, "head: leveldb: not found", strings.TrimSpace(string(res))) } +func callTx(t *testing.T) { + var blockRef = tx.NewBlockRef(0) + var chainTag = repo.ChainTag() + var expiration = uint32(10) + var gas = uint64(21000) + + for _, testTx := range []*tx.Transaction{ + new(tx.Builder). + BlockRef(blockRef). + ChainTag(chainTag). + Expiration(expiration). + Gas(gas). + Build(), + new(tx.Builder). + BlockRef(blockRef). + ChainTag(chainTag). + Expiration(expiration). + Clause(tx.NewClause(&genesis.DevAccounts()[0].Address).WithValue(big.NewInt(1234))). + Gas(gas). + Build(), + new(tx.Builder). + BlockRef(blockRef). + ChainTag(chainTag). + Expiration(expiration). + Clause( + tx.NewClause(&genesis.DevAccounts()[0].Address).WithValue(big.NewInt(1234)), + ). + Clause( + tx.NewClause(&genesis.DevAccounts()[0].Address).WithValue(big.NewInt(1234)), + ). + Gas(2 * gas). // 2 clauses of value transfer + Build(), + } { + txCall := transactions.ConvertCallTransaction(testTx, nil, &genesis.DevAccounts()[0].Address, nil) + + res := httpPostAndCheckResponseStatus(t, ts.URL+"/transactions/call", txCall, 200) + var callReceipt transactions.CallReceipt + if err := json.Unmarshal(res, &callReceipt); err != nil { + t.Fatal(err) + } + validateTxCall(t, testTx, &callReceipt, &genesis.DevAccounts()[0].Address, nil) + } +} + +func invalidCallTx(t *testing.T) { + var chainTag = repo.ChainTag() + //var expiration = uint32(10) + var gas = uint64(21000) + var sendAddr = &genesis.DevAccounts()[0].Address + + for _, tc := range []struct { + testTx *transactions.Transaction + errMsg string + }{ + { + testTx: transactions.ConvertCallTransaction(new(tx.Builder). + Gas(gas). + Build(), + nil, sendAddr, nil), + errMsg: "chain tag mismatch", + }, + //{ + // testTx: transactions.ConvertCallTransaction(new(tx.Builder). + // ChainTag(chainTag). + // Expiration(0). + // Gas(gas). + // Build(), + // nil, sendAddr, nil), + // errMsg: "chain tag mismatch", + //}, + { + testTx: transactions.ConvertCallTransaction(new(tx.Builder). + ChainTag(chainTag). + Gas(gas). + Build(), + nil, &thor.Address{}, nil), + errMsg: "no Origin address specified", + }, + { + testTx: transactions.ConvertCallTransaction(new(tx.Builder). + ChainTag(chainTag). + Gas(gas). + Clause(tx.NewClause(nil).WithData(make([]byte, 64*1024+1))). + Build(), + nil, sendAddr, nil), + errMsg: "size too large", + }, + } { + t.Run(tc.errMsg, func(t *testing.T) { + res := httpPostAndCheckResponseStatus(t, ts.URL+"/transactions/call", tc.testTx, 500) + assert.Equal(t, tc.errMsg, strings.TrimSpace(string(res))) + }) + } +} + +func validateTxCall(t *testing.T, callTx *tx.Transaction, callRcpt *transactions.CallReceipt, callAddr, delegator *thor.Address) { + assert.Equal(t, callTx.ID(), callRcpt.TxID) + assert.Equal(t, *callAddr, callRcpt.TxOrigin) + + if delegator != nil { + assert.Equal(t, delegator.String(), callRcpt.GasPayer.String()) + } else { + assert.Equal(t, callAddr.String(), callRcpt.GasPayer.String()) + } + + assert.Equal(t, len(callTx.Clauses()), len(callRcpt.Outputs)) +} + func httpPostAndCheckResponseStatus(t *testing.T, url string, obj interface{}, responseStatusCode int) []byte { data, err := json.Marshal(obj) if err != nil { @@ -349,7 +466,7 @@ func initTransactionServer(t *testing.T) { t.Fatal(e) } - transactions.New(repo, mempool).Mount(router, "/transactions") + transactions.New(repo, stater, mempool, solo.NewBFTEngine(repo)).Mount(router, "/transactions") ts = httptest.NewServer(router) } diff --git a/api/transactions/types.go b/api/transactions/types.go index 7aa3f822e..793d8783c 100644 --- a/api/transactions/types.go +++ b/api/transactions/types.go @@ -7,6 +7,7 @@ package transactions import ( "fmt" + "math/big" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" @@ -83,12 +84,9 @@ type rawTransaction struct { Meta *TxMeta `json:"meta"` } -// convertTransaction convert a raw transaction into a json format transaction -func convertTransaction(tx *tx.Transaction, header *block.Header) *Transaction { - //tx origin - origin, _ := tx.Origin() - delegator, _ := tx.Delegator() - +// ConvertCallTransaction convert a raw transaction into a json format transaction +// allows to specify the origin and delegator +func ConvertCallTransaction(tx *tx.Transaction, header *block.Header, origin *thor.Address, delegator *thor.Address) *Transaction { cls := make(Clauses, len(tx.Clauses())) for i, c := range tx.Clauses() { cls[i] = convertClause(c) @@ -97,7 +95,7 @@ func convertTransaction(tx *tx.Transaction, header *block.Header) *Transaction { t := &Transaction{ ChainTag: tx.ChainTag(), ID: tx.ID(), - Origin: origin, + Origin: *origin, BlockRef: hexutil.Encode(br[:]), Expiration: tx.Expiration(), Nonce: math.HexOrDecimal64(tx.Nonce()), @@ -119,6 +117,14 @@ func convertTransaction(tx *tx.Transaction, header *block.Header) *Transaction { return t } +// ConvertTransaction convert a raw transaction into a json format transaction +func ConvertTransaction(tx *tx.Transaction, header *block.Header) *Transaction { + //tx origin + origin, _ := tx.Origin() + delegator, _ := tx.Delegator() + return ConvertCallTransaction(tx, header, &origin, delegator) +} + type TxMeta struct { BlockID thor.Bytes32 `json:"blockID"` BlockNumber uint32 `json:"blockNumber"` @@ -144,6 +150,19 @@ type Receipt struct { Outputs []*Output `json:"outputs"` } +// CallReceipt for json marshal +type CallReceipt struct { + GasUsed uint64 `json:"gasUsed"` + GasPayer thor.Address `json:"gasPayer"` + Paid *math.HexOrDecimal256 `json:"paid"` + Reward *math.HexOrDecimal256 `json:"reward"` + Reverted bool `json:"reverted"` + TxID thor.Bytes32 `json:"txID"` + TxOrigin thor.Address `json:"txOrigin"` + Outputs []*Output `json:"outputs"` + VmError string `json:"vmError"` +} + // Output output of clause execution. type Output struct { ContractAddress *thor.Address `json:"contractAddress"` @@ -165,7 +184,7 @@ type Transfer struct { Amount *math.HexOrDecimal256 `json:"amount"` } -// ConvertReceipt convert a raw clause into a jason format clause +// ConvertReceipt convert a raw clause into a json format clause func convertReceipt(txReceipt *tx.Receipt, header *block.Header, tx *tx.Transaction) (*Receipt, error) { reward := math.HexOrDecimal256(*txReceipt.Reward) paid := math.HexOrDecimal256(*txReceipt.Paid) @@ -220,3 +239,112 @@ func convertReceipt(txReceipt *tx.Receipt, header *block.Header, tx *tx.Transact } return receipt, nil } + +// convertCallReceipt converts a tx.Receipt into a transaction.CallReceipt +func convertCallReceipt( + txReceipt *tx.Receipt, + tx *Transaction, + callAddr *thor.Address, +) (*CallReceipt, error) { + reward := math.HexOrDecimal256(*txReceipt.Reward) + paid := math.HexOrDecimal256(*txReceipt.Paid) + origin := callAddr + + receipt := &CallReceipt{ + GasUsed: txReceipt.GasUsed, + GasPayer: txReceipt.GasPayer, + Paid: &paid, + Reward: &reward, + Reverted: txReceipt.Reverted, + TxOrigin: *origin, + TxID: tx.ID, + } + receipt.Outputs = make([]*Output, len(txReceipt.Outputs)) + for i, output := range txReceipt.Outputs { + clause := tx.Clauses[i] + var contractAddr *thor.Address + if clause.To == nil { + cAddr := thor.CreateContractAddress(tx.ID, uint32(i), 0) + contractAddr = &cAddr + } + otp := &Output{contractAddr, + make([]*Event, len(output.Events)), + make([]*Transfer, len(output.Transfers)), + } + for j, txEvent := range output.Events { + event := &Event{ + Address: txEvent.Address, + Data: hexutil.Encode(txEvent.Data), + } + event.Topics = make([]thor.Bytes32, len(txEvent.Topics)) + copy(event.Topics, txEvent.Topics) + otp.Events[j] = event + } + for j, txTransfer := range output.Transfers { + transfer := &Transfer{ + Sender: txTransfer.Sender, + Recipient: txTransfer.Recipient, + Amount: (*math.HexOrDecimal256)(txTransfer.Amount), + } + otp.Transfers[j] = transfer + } + receipt.Outputs[i] = otp + } + return receipt, nil +} + +func convertErrorCallReceipt( + vmErr error, + tx *Transaction, + callAddr *thor.Address, +) (*CallReceipt, error) { + origin := callAddr + + receipt := &CallReceipt{ + Reverted: true, + TxOrigin: *origin, + TxID: tx.ID, + VmError: vmErr.Error(), + } + receipt.Outputs = make([]*Output, len(tx.Clauses)) + for i := range tx.Clauses { + clause := tx.Clauses[i] + var contractAddr *thor.Address + if clause.To == nil { + cAddr := thor.CreateContractAddress(tx.ID, uint32(i), 0) + contractAddr = &cAddr + } + + receipt.Outputs[i] = &Output{ContractAddress: contractAddr} + } + return receipt, nil +} + +// convertToTxTransaction converts a transaction.Transaction into a tx.Transaction +func convertToTxTransaction(incomingTx *Transaction) (*tx.Transaction, error) { + //blockRef, err := thor.ParseBytes32(incomingTx.BlockRef) + //if err != nil { + // return nil, fmt.Errorf("unable to parse block ref: %w", err) + //} + + convertedTxBuilder := new(tx.Builder). + ChainTag(incomingTx.ChainTag). + //Features(incomingTx). // TODO hook in the future + Nonce(uint64(incomingTx.Nonce)). + //BlockRef(tx.NewBlockRefFromID(blockRef)). // TODO hook in the future + Expiration(incomingTx.Expiration). + GasPriceCoef(incomingTx.GasPriceCoef). + Gas(incomingTx.Gas). + DependsOn(incomingTx.DependsOn) + + for _, c := range incomingTx.Clauses { + value := big.Int(c.Value) + dataVal, err := hexutil.Decode(c.Data) + if err != nil { + return nil, fmt.Errorf("unable to decode clause data: %w", err) + } + convertedTxBuilder.Clause(tx.NewClause(c.To).WithValue(&value).WithData(dataVal)) + } + + return convertedTxBuilder.Build(), nil +} diff --git a/runtime/resolved_tx.go b/runtime/resolved_tx.go index 3c3b797b0..ce1397c5e 100644 --- a/runtime/resolved_tx.go +++ b/runtime/resolved_tx.go @@ -67,6 +67,42 @@ func ResolveTransaction(tx *tx.Transaction) (*ResolvedTransaction, error) { }, nil } +// ResolveCallTransaction resolves the transaction and performs basic validation. +// Signed tx's will be ignored +func ResolveCallTransaction(tx *tx.Transaction, callAddr *thor.Address, delegator *thor.Address) (*ResolvedTransaction, error) { + var err error + + intrinsicGas, err := tx.IntrinsicGas() + if err != nil { + return nil, err + } + if tx.Gas() < intrinsicGas { + return nil, errors.New("intrinsic gas exceeds provided gas") + } + + clauses := tx.Clauses() + sumValue := new(big.Int) + for _, clause := range clauses { + value := clause.Value() + if value.Sign() < 0 { + return nil, errors.New("clause with negative value") + } + + sumValue.Add(sumValue, value) + if sumValue.Cmp(math.MaxBig256) > 0 { + return nil, errors.New("tx value too large") + } + } + + return &ResolvedTransaction{ + tx, + *callAddr, + delegator, + intrinsicGas, + clauses, + }, nil +} + // CommonTo returns common 'To' field of clauses if any. // Nil returned if no common 'To'. func (r *ResolvedTransaction) CommonTo() *thor.Address { diff --git a/runtime/runtime.go b/runtime/runtime.go index fac4d3096..efa6bd8f7 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -375,6 +375,134 @@ func (rt *Runtime) ExecuteTransaction(tx *tx.Transaction) (receipt *tx.Receipt, return executor.Finalize() } +func (rt *Runtime) CallTransaction(tx *tx.Transaction, callAddr *thor.Address, delegator *thor.Address) (receipt *tx.Receipt, err error) { + executor, err := rt.PrepareCallTransaction(tx, callAddr, delegator) + if err != nil { + return nil, err + } + for executor.HasNextClause() { + exec, _ := executor.PrepareNext() + if _, _, err := exec(); err != nil { + return nil, err + } + } + return executor.Finalize() +} + +// PrepareTransaction prepare to execute tx. +func (rt *Runtime) PrepareCallTransaction(tx *tx.Transaction, address *thor.Address, delegator *thor.Address) (*TransactionExecutor, error) { + resolvedTx, err := ResolveCallTransaction(tx, address, delegator) + if err != nil { + return nil, err + } + + baseGasPrice, gasPrice, payer, returnGas, err := resolvedTx.BuyGas(rt.state, rt.ctx.Time) + if err != nil { + return nil, err + } + + txCtx, err := resolvedTx.ToContext(gasPrice, payer, rt.ctx.Number, rt.chain.GetBlockID) + if err != nil { + return nil, err + } + + // ResolveTransaction has checked that tx.Gas() >= IntrinsicGas + leftOverGas := tx.Gas() - resolvedTx.IntrinsicGas + // checkpoint to be reverted when clause failure. + checkpoint := rt.state.NewCheckpoint() + + txOutputs := make([]*Tx.Output, 0, len(resolvedTx.Clauses)) + reverted := false + finalized := false + + hasNext := func() bool { + return !reverted && len(txOutputs) < len(resolvedTx.Clauses) + } + + return &TransactionExecutor{ + HasNextClause: hasNext, + PrepareNext: func() (exec func() (uint64, *Output, error), interrupt func()) { + nextClauseIndex := uint32(len(txOutputs)) + execFunc, interrupt := rt.PrepareClause(resolvedTx.Clauses[nextClauseIndex], nextClauseIndex, leftOverGas, txCtx) + + exec = func() (gasUsed uint64, output *Output, err error) { + output, _, err = execFunc() + if err != nil { + return 0, nil, err + } + gasUsed = leftOverGas - output.LeftOverGas + leftOverGas = output.LeftOverGas + + // Apply refund counter, capped to half of the used gas. + refund := gasUsed / 2 + if refund > output.RefundGas { + refund = output.RefundGas + } + + // won't overflow + leftOverGas += refund + + if output.VMErr != nil { + // vm exception here + // revert all executed clauses + rt.state.RevertTo(checkpoint) + reverted = true + txOutputs = nil + return + } + txOutputs = append(txOutputs, &Tx.Output{Events: output.Events, Transfers: output.Transfers}) + return + } + + return + }, + Finalize: func() (*Tx.Receipt, error) { + if hasNext() { + return nil, errors.New("not all clauses processed") + } + if finalized { + return nil, errors.New("already finalized") + } + finalized = true + + receipt := &Tx.Receipt{ + Reverted: reverted, + Outputs: txOutputs, + GasUsed: tx.Gas() - leftOverGas, + GasPayer: payer, + } + + receipt.Paid = new(big.Int).Mul(new(big.Int).SetUint64(receipt.GasUsed), gasPrice) + + if err := returnGas(leftOverGas); err != nil { + return nil, err + } + + // reward + rewardRatio, err := builtin.Params.Native(rt.state).Get(thor.KeyRewardRatio) + if err != nil { + return nil, err + } + provedWork, err := tx.ProvedWork(rt.ctx.Number-1, rt.chain.GetBlockID) + if err != nil { + return nil, err + } + overallGasPrice := tx.OverallGasPrice(baseGasPrice, provedWork) + + reward := new(big.Int).SetUint64(receipt.GasUsed) + reward.Mul(reward, overallGasPrice) + reward.Mul(reward, rewardRatio) + reward.Div(reward, big.NewInt(1e18)) + if err := builtin.Energy.Native(rt.state, rt.ctx.Time).Add(rt.ctx.Beneficiary, reward); err != nil { + return nil, err + } + + receipt.Reward = reward + return receipt, nil + }, + }, nil +} + // PrepareTransaction prepare to execute tx. func (rt *Runtime) PrepareTransaction(tx *tx.Transaction) (*TransactionExecutor, error) { resolvedTx, err := ResolveTransaction(tx) From 8ff45c0ea9be16ec77c9863793ad16f272c901f4 Mon Sep 17 00:00:00 2001 From: otherview Date: Wed, 28 Aug 2024 16:48:30 +0100 Subject: [PATCH 2/2] passing forkconfig --- api/api.go | 2 +- api/transactions/transactions.go | 24 +++++++++++++----------- api/transactions/transactions_test.go | 4 ++-- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/api/api.go b/api/api.go index b666e89ad..0c94f736c 100644 --- a/api/api.go +++ b/api/api.go @@ -81,7 +81,7 @@ func New( } blocks.New(repo, bft). Mount(router, "/blocks") - transactions.New(repo, stater, txPool, bft). + transactions.New(repo, stater, txPool, bft, forkConfig). Mount(router, "/transactions") debug.New(repo, stater, forkConfig, callGasLimit, allowCustomTracer, bft, allowedTracers). Mount(router, "/debug") diff --git a/api/transactions/transactions.go b/api/transactions/transactions.go index 322641094..ef56c415e 100644 --- a/api/transactions/transactions.go +++ b/api/transactions/transactions.go @@ -27,18 +27,20 @@ import ( const maxTxSize = 64 * 1024 type Transactions struct { - repo *chain.Repository - pool *txpool.TxPool - stater *state.Stater - bft bft.Finalizer + repo *chain.Repository + pool *txpool.TxPool + stater *state.Stater + bft bft.Finalizer + forkConfig thor.ForkConfig } -func New(repo *chain.Repository, stater *state.Stater, pool *txpool.TxPool, bft bft.Finalizer) *Transactions { +func New(repo *chain.Repository, stater *state.Stater, pool *txpool.TxPool, bft bft.Finalizer, forkConfig thor.ForkConfig) *Transactions { return &Transactions{ - repo: repo, - stater: stater, - pool: pool, - bft: bft, + repo: repo, + stater: stater, + pool: pool, + bft: bft, + forkConfig: forkConfig, } } @@ -234,7 +236,7 @@ func (t *Transactions) txCall( ) (*CallReceipt, error) { callAddr := txCallMsg.Origin if callAddr.String() == (thor.Address{}).String() { - return nil, fmt.Errorf("no Origin address specified") + return nil, fmt.Errorf("no origin address specified") } // todo handle the txCallMsg.Delegator @@ -265,7 +267,7 @@ func (t *Transactions) txCall( GasLimit: header.GasLimit(), TotalScore: header.TotalScore(), }, - thor.NoFork) + t.forkConfig) receipt, err := rt.CallTransaction(txCallData, &callAddr, nil) // TODO hook delegator if err != nil { diff --git a/api/transactions/transactions_test.go b/api/transactions/transactions_test.go index 94a908bd7..f0d11eb60 100644 --- a/api/transactions/transactions_test.go +++ b/api/transactions/transactions_test.go @@ -345,7 +345,7 @@ func invalidCallTx(t *testing.T) { Gas(gas). Build(), nil, &thor.Address{}, nil), - errMsg: "no Origin address specified", + errMsg: "no origin address specified", }, { testTx: transactions.ConvertCallTransaction(new(tx.Builder). @@ -466,7 +466,7 @@ func initTransactionServer(t *testing.T) { t.Fatal(e) } - transactions.New(repo, stater, mempool, solo.NewBFTEngine(repo)).Mount(router, "/transactions") + transactions.New(repo, stater, mempool, solo.NewBFTEngine(repo), thor.NoFork).Mount(router, "/transactions") ts = httptest.NewServer(router) }