// promoteTx adds a transaction to the pending (processable) list of transactions. // // Note, this method assumes the pool lock is held! func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) { // Init delayed since tx pool could have been started before any state sync if pool.pendingState == nil { pool.resetState() } // Try to insert the transaction into the pending queue if pool.pending[addr] == nil { pool.pending[addr] = newTxList(true) } list := pool.pending[addr] inserted, old := list.Add(tx) if !inserted { // An older transaction was better, discard this delete(pool.all, hash) return } // Otherwise discard any previous transaction and mark this if old != nil { delete(pool.all, old.Hash()) } pool.all[hash] = tx // Failsafe to work around direct pending inserts (tests) // Set the potentially new pending nonce and notify any subsystems of the new tx pool.beats[addr] = time.Now() pool.pendingState.SetNonce(addr, tx.Nonce()+1) go pool.eventMux.Post(TxPreEvent{tx}) }
func (self *BlockProcessor) ApplyTransaction(gp GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) { _, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, header), tx, gp) if err != nil { return nil, nil, err } // Update the state with pending changes statedb.SyncIntermediate() usedGas.Add(usedGas, gas) receipt := types.NewReceipt(statedb.Root().Bytes(), usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = new(big.Int).Set(gas) if MessageCreatesContract(tx) { from, _ := tx.From() receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce()) } logs := statedb.GetLogs(tx.Hash()) receipt.SetLogs(logs) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) glog.V(logger.Debug).Infoln(receipt) // Notify all subscribers if !transientProcess { go self.eventMux.Post(TxPostEvent{tx}) go self.eventMux.Post(logs) } return receipt, gas, err }
func NewTx(tx *types.Transaction) *Transaction { sender, err := tx.From() if err != nil { return nil } hash := tx.Hash().Hex() var receiver string if to := tx.To(); to != nil { receiver = to.Hex() } else { from, _ := tx.From() receiver = crypto.CreateAddress(from, tx.Nonce()).Hex() } createsContract := core.MessageCreatesContract(tx) var data string if createsContract { data = strings.Join(core.Disassemble(tx.Data()), "\n") } else { data = common.ToHex(tx.Data()) } return &Transaction{ref: tx, Hash: hash, Value: common.CurrencyToString(tx.Value()), Address: receiver, Contract: createsContract, Gas: tx.Gas().String(), GasPrice: tx.GasPrice().String(), Data: data, Sender: sender.Hex(), CreatesContract: createsContract, RawData: common.ToHex(tx.Data())} }
// Put inserts a new transaction into the map, also updating the map's nonce // index. If a transaction already exists with the same nonce, it's overwritten. func (m *txSortedMap) Put(tx *types.Transaction) { nonce := tx.Nonce() if m.items[nonce] == nil { heap.Push(m.index, nonce) } m.items[nonce], m.cache = tx, nil }
func (self *XEth) PushTx(encodedTx string) (string, error) { tx := new(types.Transaction) err := rlp.DecodeBytes(common.FromHex(encodedTx), tx) if err != nil { glog.V(logger.Error).Infoln(err) return "", err } err = self.backend.TxPool().Add(tx) if err != nil { return "", err } if tx.To() == nil { from, err := tx.From() if err != nil { return "", err } addr := crypto.CreateAddress(from, tx.Nonce()) glog.V(logger.Info).Infof("Tx(%x) created: %x\n", tx.Hash(), addr) } else { glog.V(logger.Info).Infof("Tx(%x) to: %x\n", tx.Hash(), tx.To()) } return tx.Hash().Hex(), nil }
// validateTx checks whether a transaction is valid according // to the consensus rules. func (pool *TxPool) validateTx(tx *types.Transaction) error { // Validate sender var ( from common.Address err error ) // Drop transactions under our own minimal accepted gas price if pool.minGasPrice.Cmp(tx.GasPrice()) > 0 { return ErrCheap } // Validate the transaction sender and it's sig. Throw // if the from fields is invalid. if from, err = tx.From(); err != nil { return ErrInvalidSender } // Make sure the account exist. Non existent accounts // haven't got funds and well therefor never pass. currentState, err := pool.currentState() if err != nil { return err } if !currentState.HasAccount(from) { return ErrNonExistentAccount } // Last but not least check for nonce errors if currentState.GetNonce(from) > tx.Nonce() { return ErrNonce } // Check the transaction doesn't exceed the current // block limit gas. if pool.gasLimit().Cmp(tx.Gas()) < 0 { return ErrGasLimit } // Transactions can't be negative. This may never happen // using RLP decoded transactions but may occur if you create // a transaction using the RPC for example. if tx.Value().Cmp(common.Big0) < 0 { return ErrNegativeValue } // Transactor should have enough funds to cover the costs // cost == V + GP * GL if currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { return ErrInsufficientFunds } // Should supply enough intrinsic gas if tx.Gas().Cmp(IntrinsicGas(tx.Data())) < 0 { return ErrIntrinsicGas } return nil }
// validateTx checks whether a transaction is valid according // to the consensus rules. func (pool *TxPool) validateTx(tx *types.Transaction) error { local := pool.localTx.contains(tx.Hash()) // Drop transactions under our own minimal accepted gas price if !local && pool.minGasPrice.Cmp(tx.GasPrice()) > 0 { return ErrCheap } currentState, err := pool.currentState() if err != nil { return err } from, err := tx.From() if err != nil { return ErrInvalidSender } // Make sure the account exist. Non existent accounts // haven't got funds and well therefor never pass. if !currentState.Exist(from) { return ErrNonExistentAccount } // Last but not least check for nonce errors if currentState.GetNonce(from) > tx.Nonce() { return ErrNonce } // Check the transaction doesn't exceed the current // block limit gas. if pool.gasLimit().Cmp(tx.Gas()) < 0 { return ErrGasLimit } // Transactions can't be negative. This may never happen // using RLP decoded transactions but may occur if you create // a transaction using the RPC for example. if tx.Value().Cmp(common.Big0) < 0 { return ErrNegativeValue } // Transactor should have enough funds to cover the costs // cost == V + GP * GL if currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { return ErrInsufficientFunds } intrGas := IntrinsicGas(tx.Data(), MessageCreatesContract(tx), pool.homestead) if tx.Gas().Cmp(intrGas) < 0 { return ErrIntrinsicGas } return nil }
// Remove deletes a transaction from the maintained list, returning whether the // transaction was found, and also returning any transaction invalidated due to // the deletion (strict mode only). func (l *txList) Remove(tx *types.Transaction) (bool, types.Transactions) { // Remove the transaction from the set nonce := tx.Nonce() if removed := l.txs.Remove(nonce); !removed { return false, nil } // In strict mode, filter out non-executable transactions if l.strict { return true, l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce }) } return true, nil }
// Add tries to insert a new transaction into the list, returning whether the // transaction was accepted, and if yes, any previous transaction it replaced. // // If the new transaction is accepted into the list, the lists' cost threshold // is also potentially updated. func (l *txList) Add(tx *types.Transaction) (bool, *types.Transaction) { // If there's an older better transaction, abort old := l.txs.Get(tx.Nonce()) if old != nil && old.GasPrice().Cmp(tx.GasPrice()) >= 0 { return false, nil } // Otherwise overwrite the old transaction with the current one l.txs.Put(tx) if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 { l.costcap = cost } return true, old }
// addTx will add a transaction to the pending (processable queue) list of transactions func (pool *TxPool) addTx(hash common.Hash, addr common.Address, tx *types.Transaction) { if _, ok := pool.pending[hash]; !ok { pool.pending[hash] = tx // Increment the nonce on the pending state. This can only happen if // the nonce is +1 to the previous one. pool.pendingState.SetNonce(addr, tx.Nonce()+1) // Notify the subscribers. This event is posted in a goroutine // because it's possible that somewhere during the post "Remove transaction" // gets called which will then wait for the global tx pool lock and deadlock. go pool.eventMux.Post(TxPreEvent{tx}) } }
func newTx(t *types.Transaction) *tx { from, _ := t.From() var to string if t := t.To(); t != nil { to = t.Hex() } return &tx{ tx: t, To: to, From: from.Hex(), Value: t.Value().String(), Nonce: strconv.Itoa(int(t.Nonce())), Data: "0x" + common.Bytes2Hex(t.Data()), GasLimit: t.Gas().String(), GasPrice: t.GasPrice().String(), Hash: t.Hash().Hex(), } }
func NewTransactionRes(tx *types.Transaction) *TransactionRes { if tx == nil { return nil } var v = new(TransactionRes) v.Hash = newHexData(tx.Hash()) v.Nonce = newHexNum(tx.Nonce()) // v.BlockHash = // v.BlockNumber = // v.TxIndex = from, _ := tx.From() v.From = newHexData(from) v.To = newHexData(tx.To()) v.Value = newHexNum(tx.Value()) v.Gas = newHexNum(tx.Gas()) v.GasPrice = newHexNum(tx.GasPrice()) v.Input = newHexData(tx.Data()) return v }
// ApplyTransaction attemps to apply a transaction to the given state database // and uses the input parameters for its environment. // // ApplyTransactions returns the generated receipts and vm logs during the // execution of the state transition phase. func ApplyTransaction(bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int) (*types.Receipt, vm.Logs, *big.Int, error) { _, gas, err := ApplyMessage(NewEnv(statedb, bc, tx, header), tx, gp) if err != nil { return nil, nil, nil, err } // Update the state with pending changes usedGas.Add(usedGas, gas) receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = new(big.Int).Set(gas) if MessageCreatesContract(tx) { from, _ := tx.From() receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce()) } logs := statedb.GetLogs(tx.Hash()) receipt.Logs = logs receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) glog.V(logger.Debug).Infoln(receipt) return receipt, logs, gas, err }
func verifyTxFields(txTest TransactionTest, decodedTx *types.Transaction) (err error) { defer func() { if recovered := recover(); recovered != nil { buf := make([]byte, 64<<10) buf = buf[:runtime.Stack(buf, false)] err = fmt.Errorf("%v\n%s", recovered, buf) } }() var ( decodedSender common.Address ) chainConfig := &core.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock} if chainConfig.IsHomestead(common.String2Big(txTest.Blocknumber)) { decodedSender, err = decodedTx.From() } else { decodedSender, err = decodedTx.FromFrontier() } if err != nil { return err } expectedSender := mustConvertAddress(txTest.Sender) if expectedSender != decodedSender { return fmt.Errorf("Sender mismatch: %v %v", expectedSender, decodedSender) } expectedData := mustConvertBytes(txTest.Transaction.Data) if !bytes.Equal(expectedData, decodedTx.Data()) { return fmt.Errorf("Tx input data mismatch: %#v %#v", expectedData, decodedTx.Data()) } expectedGasLimit := mustConvertBigInt(txTest.Transaction.GasLimit, 16) if expectedGasLimit.Cmp(decodedTx.Gas()) != 0 { return fmt.Errorf("GasLimit mismatch: %v %v", expectedGasLimit, decodedTx.Gas()) } expectedGasPrice := mustConvertBigInt(txTest.Transaction.GasPrice, 16) if expectedGasPrice.Cmp(decodedTx.GasPrice()) != 0 { return fmt.Errorf("GasPrice mismatch: %v %v", expectedGasPrice, decodedTx.GasPrice()) } expectedNonce := mustConvertUint(txTest.Transaction.Nonce, 16) if expectedNonce != decodedTx.Nonce() { return fmt.Errorf("Nonce mismatch: %v %v", expectedNonce, decodedTx.Nonce()) } v, r, s := decodedTx.SignatureValues() expectedR := mustConvertBigInt(txTest.Transaction.R, 16) if r.Cmp(expectedR) != 0 { return fmt.Errorf("R mismatch: %v %v", expectedR, r) } expectedS := mustConvertBigInt(txTest.Transaction.S, 16) if s.Cmp(expectedS) != 0 { return fmt.Errorf("S mismatch: %v %v", expectedS, s) } expectedV := mustConvertUint(txTest.Transaction.V, 16) if uint64(v) != expectedV { return fmt.Errorf("V mismatch: %v %v", expectedV, v) } expectedTo := mustConvertAddress(txTest.Transaction.To) if decodedTx.To() == nil { if expectedTo != common.BytesToAddress([]byte{}) { // "empty" or "zero" address return fmt.Errorf("To mismatch when recipient is nil (contract creation): %v", expectedTo) } } else { if expectedTo != *decodedTx.To() { return fmt.Errorf("To mismatch: %v %v", expectedTo, *decodedTx.To()) } } expectedValue := mustConvertBigInt(txTest.Transaction.Value, 16) if expectedValue.Cmp(decodedTx.Value()) != 0 { return fmt.Errorf("Value mismatch: %v %v", expectedValue, decodedTx.Value()) } return nil }