// Adds a coin.Transaction to the pool, or updates an existing one's timestamps // Returns an error if txn is invalid, and whether the transaction already // existed in the pool. func (self *UnconfirmedTxnPool) RecordTxn(bc *coin.Blockchain, t coin.Transaction, addrs map[coin.Address]byte, maxSize int, burnFactor uint64) (error, bool) { if err := VerifyTransaction(bc, &t, maxSize, burnFactor); err != nil { return err, false } if err := bc.VerifyTransaction(t); err != nil { return err, false } // Update if we already have this txn ut, ok := self.Txns[t.Hash()] if ok { now := util.Now() ut.Received = now ut.Checked = now self.Txns[ut.Txn.Hash()] = ut return nil, true } // Add txn to index self.Txns[t.Hash()] = self.createUnconfirmedTxn(&bc.Unspent, t, addrs) // Add predicted unspents uxs := coin.CreateExpectedUnspents(t) for i, _ := range uxs { self.Unspent.Add(uxs[i]) } return nil, false }
// Adds a coin.Transaction to the pool, or updates an existing one's timestamps // Returns an error if txn is invalid, and whether the transaction already // existed in the pool. func (self *UnconfirmedTxnPool) RecordTxn(bc *coin.Blockchain, t coin.Transaction, addrs map[cipher.Address]byte, maxSize int, burnFactor uint64) (error, bool) { if err := VerifyTransaction(bc, &t, maxSize, burnFactor); err != nil { return err, false } if err := bc.VerifyTransaction(t); err != nil { return err, false } // Update if we already have this txn h := t.Hash() ut, ok := self.Txns[h] if ok { now := util.Now() ut.Received = now ut.Checked = now self.Txns[h] = ut return nil, true } // Add txn to index self.Txns[h] = self.createUnconfirmedTxn(&bc.Unspent, t, addrs) // Add predicted unspents self.Unspent[h] = coin.CreateUnspents(bc.Head().Head, t) return nil, false }
// Adds a coin.Transaction to the pool, or updates an existing one's timestamps // Returns an error if txn is invalid, and whether the transaction already // existed in the pool. func (self *UnconfirmedTxnPool) InjectTxn(bc *coin.Blockchain, t coin.Transaction) (error, bool) { if err := t.Verify(); err != nil { return err, false } if err := VerifyTransactionFee(bc, &t); err != nil { return err, false } if err := bc.VerifyTransaction(t); err != nil { return err, false } // Update if we already have this txn h := t.Hash() ut, ok := self.Txns[h] if ok { now := util.Now() ut.Received = now ut.Checked = now self.Txns[h] = ut return nil, true } // Add txn to index self.Txns[h] = self.createUnconfirmedTxn(&bc.Unspent, t) // Add predicted unspents self.Unspent[h] = coin.CreateUnspents(bc.Head().Head, t) return nil, false }
func assertValidUnspent(t *testing.T, bc *coin.Blockchain, unspent *coin.UnspentPool, tx coin.Transaction) { expect := bc.TxUxOut(tx, coin.BlockHeader{}) assert.NotEqual(t, len(expect), 0) assert.Equal(t, len(expect), len(unspent.Arr)) for _, ux := range expect { assert.True(t, unspent.Has(ux.Hash())) } }
// Performs additional transaction verification at the unconfirmed pool level. // This checks tunable parameters that should prevent the transaction from // entering the blockchain, but cannot be done at the blockchain level because // they may be changed. func VerifyTransaction(bc *coin.Blockchain, t *coin.Transaction, maxSize int, burnFactor uint64) error { if t.Size() > maxSize { return errors.New("Transaction too large") } if fee, err := bc.TransactionFee(t); err != nil { return err } else if burnFactor != 0 && t.OutputHours()/burnFactor > fee { return errors.New("Transaction fee minimum not met") } return nil }
// Performs additional transaction verification at the unconfirmed pool level. // This checks tunable parameters that should prevent the transaction from // entering the blockchain, but cannot be done at the blockchain level because // they may be changed. func VerifyTransactionFee(bc *coin.Blockchain, t *coin.Transaction) error { fee, err := bc.TransactionFee(t) if err != nil { return err } //calculate total number of coinhours var total uint64 = t.OutputHours() + fee //make sure at least half the coin hours are destroyed if fee < total/BurnFactor { return errors.New("Transaction coinhour fee minimum not met") } return nil }
// Checks all unconfirmed txns against the blockchain. maxAge is how long // we'll hold a txn regardless of whether it has been invalidated. // checkPeriod is how often we check the txn against the blockchain. func (self *UnconfirmedTxnPool) Refresh(bc *coin.Blockchain, checkPeriod int) { now := time.Now().Unix() toRemove := make([]cipher.SHA256, 0) for k, t := range self.Txns { if now-t.Checked >= int64(checkPeriod) { if bc.VerifyTransaction(t.Txn) == nil { t.Checked = now self.Txns[k] = t } else { toRemove = append(toRemove, k) } } } self.removeTxns(toRemove) }
// Checks all unconfirmed txns against the blockchain. maxAge is how long // we'll hold a txn regardless of whether it has been invalidated. // checkPeriod is how often we check the txn against the blockchain. func (self *UnconfirmedTxnPool) Refresh(bc *coin.Blockchain, checkPeriod, maxAge time.Duration) { now := util.Now() toRemove := make([]coin.SHA256, 0) for k, t := range self.Txns { if now.Sub(t.Received) >= maxAge { toRemove = append(toRemove, k) } else if now.Sub(t.Checked) >= checkPeriod { if bc.VerifyTransaction(t.Txn) == nil { t.Checked = now self.Txns[k] = t } else { toRemove = append(toRemove, k) } } } self.removeTxns(bc, toRemove) }
func assertValidUnspent(t *testing.T, bc *coin.Blockchain, unspent TxnUnspents, tx coin.Transaction) { expect := coin.CreateUnspents(bc.Head().Head, tx) assert.NotEqual(t, len(expect), 0) sum := 0 for _, uxs := range unspent { sum += len(uxs) } assert.Equal(t, len(expect), sum) uxs := unspent[tx.Hash()] for _, ux := range expect { found := false for _, u := range uxs { if u.Hash() == ux.Hash() { found = true break } } assert.True(t, found) } }