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())} }
// validate and queue transactions. func (self *TxPool) add(tx *types.Transaction) error { hash := tx.Hash() if self.pending[hash] != nil { return fmt.Errorf("Known transaction (%x)", hash[:4]) } err := self.validateTx(tx) if err != nil { return err } self.queueTx(hash, tx) if glog.V(logger.Debug) { var toname string if to := tx.To(); to != nil { toname = common.Bytes2Hex(to[:4]) } else { toname = "[NEW_CONTRACT]" } // we can ignore the error here because From is // verified in ValidateTransaction. f, _ := tx.From() from := common.Bytes2Hex(f[:4]) glog.Infof("(t) %x => %s (%v) %x\n", from, toname, tx.Value, hash) } return nil }
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 }
// 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 }
// AddTx adds a transaction to the generated block. If no coinbase has // been set, the block's coinbase is set to the zero address. // // AddTx panics if the transaction cannot be executed. In addition to // the protocol-imposed limitations (gas limit, etc.), there are some // further limitations on the content of transactions that can be // added. Notably, contract code relying on the BLOCKHASH instruction // will panic during execution. func (b *BlockGen) AddTx(tx *types.Transaction) { if b.gasPool == nil { b.SetCoinbase(common.Address{}) } _, gas, err := ApplyMessage(NewEnv(b.statedb, nil, tx, b.header), tx, b.gasPool) if err != nil { panic(err) } root := b.statedb.IntermediateRoot() b.header.GasUsed.Add(b.header.GasUsed, gas) receipt := types.NewReceipt(root.Bytes(), b.header.GasUsed) logs := b.statedb.GetLogs(tx.Hash()) receipt.Logs = logs receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) b.txs = append(b.txs, tx) b.receipts = append(b.receipts, receipt) }
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 }
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 }
// add validates a transaction and inserts it into the non-executable queue for // later pending promotion and execution. func (pool *TxPool) add(tx *types.Transaction) error { // If the transaction is alreayd known, discard it hash := tx.Hash() if pool.all[hash] != nil { return fmt.Errorf("Known transaction: %x", hash[:4]) } // Otherwise ensure basic validation passes and queue it up if err := pool.validateTx(tx); err != nil { return err } pool.enqueueTx(hash, tx) // Print a log message if low enough level is set if glog.V(logger.Debug) { rcpt := "[NEW_CONTRACT]" if to := tx.To(); to != nil { rcpt = common.Bytes2Hex(to[:4]) } from, _ := tx.From() // from already verified during tx validation glog.Infof("(t) 0x%x => %s (%v) %x\n", from[:4], rcpt, tx.Value, hash) } return nil }
// 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 }
// Tests that if a transaction is dropped from the current pending pool (e.g. out // of fund), all consecutive (still valid, but not executable) transactions are // postponed back into the future queue to prevent broadcating them. func TestTransactionPostponing(t *testing.T) { // Create a test account and fund it pool, key := setupTxPool() account, _ := transaction(0, big.NewInt(0), key).From() state, _ := pool.currentState() state.AddBalance(account, big.NewInt(1000)) // Add a batch consecutive pending transactions for validation txns := []*types.Transaction{} for i := 0; i < 100; i++ { var tx *types.Transaction if i%2 == 0 { tx = transaction(uint64(i), big.NewInt(100), key) } else { tx = transaction(uint64(i), big.NewInt(500), key) } pool.addTx(tx.Hash(), account, tx) txns = append(txns, tx) } // Check that pre and post validations leave the pool as is if len(pool.pending) != len(txns) { t.Errorf("pending transaction mismatch: have %d, want %d", len(pool.pending), len(txns)) } if len(pool.queue[account]) != 0 { t.Errorf("queued transaction mismatch: have %d, want %d", len(pool.queue), 0) } pool.resetState() if len(pool.pending) != len(txns) { t.Errorf("pending transaction mismatch: have %d, want %d", len(pool.pending), len(txns)) } if len(pool.queue[account]) != 0 { t.Errorf("queued transaction mismatch: have %d, want %d", len(pool.queue), 0) } // Reduce the balance of the account, and check that transactions are reorganized state.AddBalance(account, big.NewInt(-750)) pool.resetState() if _, ok := pool.pending[txns[0].Hash()]; !ok { t.Errorf("tx %d: valid and funded transaction missing from pending pool: %v", 0, txns[0]) } if _, ok := pool.queue[account][txns[0].Hash()]; ok { t.Errorf("tx %d: valid and funded transaction present in future queue: %v", 0, txns[0]) } for i, tx := range txns[1:] { if i%2 == 1 { if _, ok := pool.pending[tx.Hash()]; ok { t.Errorf("tx %d: valid but future transaction present in pending pool: %v", i+1, tx) } if _, ok := pool.queue[account][tx.Hash()]; !ok { t.Errorf("tx %d: valid but future transaction missing from future queue: %v", i+1, tx) } } else { if _, ok := pool.pending[tx.Hash()]; ok { t.Errorf("tx %d: out-of-fund transaction present in pending pool: %v", i+1, tx) } if _, ok := pool.queue[account][tx.Hash()]; ok { t.Errorf("tx %d: out-of-fund transaction present in future queue: %v", i+1, tx) } } } }
// SetLocal marks a transaction as local, skipping gas price // check against local miner minimum in the future func (pool *TxPool) SetLocal(tx *types.Transaction) { pool.mu.Lock() defer pool.mu.Unlock() pool.localTx.add(tx.Hash()) }