// VerifyTransaction checks that the inputs to the transaction exist, // that the transaction does not create or destroy coins and that the // signatures on the transaction are valid func (bc Blockchain) VerifyTransaction(tx coin.Transaction) error { //CHECKLIST: DONE: check for duplicate ux inputs/double spending //CHECKLIST: DONE: check that inputs of transaction have not been spent //CHECKLIST: DONE: check there are no duplicate outputs // Q: why are coin hours based on last block time and not // current time? // A: no two computers will agree on system time. Need system clock // indepedent timing that everyone agrees on. fee values would depend on // local clock // Check transaction type and length // Check for duplicate outputs // Check for duplicate inputs // Check for invalid hash // Check for no inputs // Check for no outputs // Check for non 1e6 multiple coin outputs // Check for zero coin outputs // Check valid looking signatures if err := tx.Verify(); err != nil { return err } uxIn, err := bc.unspent.GetMultiple(tx.In) if err != nil { return err } // Checks whether ux inputs exist, // Check that signatures are allowed to spend inputs if err := tx.VerifyInput(uxIn); err != nil { return err } // Get the UxOuts we expect to have when the block is created. uxOut := coin.CreateUnspents(bc.Head().Head, tx) // Check that there are any duplicates within this set if uxOut.HasDupes() { return errors.New("Duplicate unspent outputs in transaction") } if DebugLevel1 { // Check that new unspents don't collide with existing. This should // also be checked in verifyTransactions for i := range uxOut { if bc.unspent.Has(uxOut[i].Hash()) { return errors.New("New unspent collides with existing unspent") } } } // Check that no coins are lost, and sufficient coins and hours are spent err = coin.VerifyTransactionSpending(bc.Time(), uxIn, uxOut) if err != nil { return err } return nil }