func SignFactoidTransaction(n uint64, tx interfaces.ITransaction) { tx.AddAuthorization(NewFactoidRCDAddress(n)) data, err := tx.MarshalBinarySig() if err != nil { panic(err) } sig := factoid.NewSingleSignatureBlock(NewPrivKey(n), data) //str, err := sig.JSONString() //fmt.Printf("sig, err - %v, %v\n", str, err) tx.SetSignatureBlock(0, sig) err = tx.Validate(1) if err != nil { panic(err) } err = tx.ValidateSignatures() if err != nil { panic(err) } }
func (b *FBlock) MarshalTrans() ([]byte, error) { var out bytes.Buffer var periodMark = 0 var i int var trans interfaces.ITransaction for i, trans = range b.Transactions { for periodMark < len(b.endOfPeriod) && b.endOfPeriod[periodMark] > 0 && // Ignore if markers are not set i == b.endOfPeriod[periodMark] { out.WriteByte(constants.MARKER) periodMark++ } data, err := trans.MarshalBinary() if err != nil { return nil, err } out.Write(data) if err != nil { return nil, err } } for periodMark < len(b.endOfPeriod) { out.WriteByte(constants.MARKER) periodMark++ } return out.Bytes(), nil }
func (w *SCWallet) AddECOutput(trans interfaces.ITransaction, address interfaces.IAddress, amount uint64) error { _, adr, err := w.getWalletEntry([]byte(constants.W_RCD_ADDRESS_HASH), address) if err != nil { adr = address } trans.AddECOutput(CreateAddress(adr), amount) return nil }
// Returns an error message about what is wrong with the transaction if it is // invalid, otherwise you are good to go. func (fs *FactoidState) Validate(index int, trans interfaces.ITransaction) error { var sums = make(map[[32]byte]uint64, 10) // Look at the sum of an address's inputs for _, input := range trans.GetInputs() { // to a transaction. bal, err := factoid.ValidateAmounts(sums[input.GetAddress().Fixed()], input.GetAmount()) if err != nil { return err } if int64(bal) > fs.State.GetF(true, input.GetAddress().Fixed()) { return fmt.Errorf("%s", "Not enough funds in input addresses for the transaction") } sums[input.GetAddress().Fixed()] = bal } return nil }
// Checks the transaction timestamp for validity in being included in the current // No node has any responsiblity to forward on transactions that do not fall within // the timeframe around a block defined by TRANSACTION_PRIOR_LIMIT and TRANSACTION_POST_LIMIT func (fs *FactoidState) ValidateTransactionAge(trans interfaces.ITransaction) error { tsblk := fs.GetCurrentBlock().GetCoinbaseTimestamp() if tsblk < 0 { return fmt.Errorf("Block has no coinbase transaction at this time") } tstrans := int64(trans.GetMilliTimestamp()) if tsblk-tstrans > constants.TRANSACTION_PRIOR_LIMIT { return fmt.Errorf("Transaction is too old to be included in the current block") } if tstrans-tsblk > constants.TRANSACTION_POST_LIMIT { return fmt.Errorf("Transaction is dated too far in the future to be included in the current block") } return nil }
func (w RCD_1) CheckSig(trans interfaces.ITransaction, sigblk interfaces.ISignatureBlock) bool { if sigblk == nil { return false } data, err := trans.MarshalBinarySig() if err != nil { return false } signature := sigblk.GetSignature(0) if signature == nil { return false } cryptosig := signature.GetSignature() if cryptosig == nil { return false } return ed25519.VerifyCanonical(&w.PublicKey, data, cryptosig) }
func (w *SCWallet) UpdateInput(trans interfaces.ITransaction, index int, address interfaces.IAddress, amount uint64) error { we, adr, err := w.getWalletEntry([]byte(constants.W_RCD_ADDRESS_HASH), address) if err != nil { return err } in, err := trans.GetInput(index) if err != nil { return err } trans.GetRCDs()[index] = we.GetRCD() // The RCD must match the (possibly) new input in.SetAddress(adr) in.SetAmount(amount) return nil }
func (b *FBlock) MarshalTrans() ([]byte, error) { var out primitives.Buffer var periodMark = 0 var i int var trans interfaces.ITransaction // for _, v := range b.GetEndOfPeriod() { // if v == 0 { // return nil, fmt.Errorf("Factoid Block is incomplete. Missing EOM markers detected: %v",b.endOfPeriod) // } // } for i, trans = range b.Transactions { for periodMark < len(b.endOfPeriod) && b.endOfPeriod[periodMark] > 0 && // Ignore if markers are not set i == b.endOfPeriod[periodMark] { out.WriteByte(constants.MARKER) periodMark++ } data, err := trans.MarshalBinary() if err != nil { return nil, err } out.Write(data) if err != nil { return nil, err } } for periodMark < len(b.endOfPeriod) { out.WriteByte(constants.MARKER) periodMark++ } return out.DeepCopyBytes(), nil }
// Only add valid transactions to the current func (fs *FactoidState) AddTransaction(index int, trans interfaces.ITransaction) error { if err := fs.Validate(index, trans); err != nil { return err } if err := fs.ValidateTransactionAge(trans); err != nil { return err } if err := fs.UpdateTransaction(true, trans); err != nil { return err } if err := fs.CurrentBlock.AddTransaction(trans); err != nil { if err != nil { return err } // We assume validity has been done elsewhere. We are maintaining the "seen" state of // all transactions here. fs.State.Replay.IsTSValid(constants.INTERNAL_REPLAY|constants.NETWORK_REPLAY, trans.GetSigHash(), trans.GetTimestamp()) fs.State.Replay.IsTSValid(constants.NETWORK_REPLAY|constants.NETWORK_REPLAY, trans.GetSigHash(), trans.GetTimestamp()) for index, eo := range trans.GetECOutputs() { pl := fs.State.ProcessLists.Get(fs.DBHeight) incBal := entryCreditBlock.NewIncreaseBalance() v := eo.GetAddress().Fixed() incBal.ECPubKey = (*primitives.ByteSlice32)(&v) incBal.NumEC = eo.GetAmount() / fs.GetCurrentBlock().GetExchRate() incBal.TXID = trans.GetSigHash() incBal.Index = uint64(index) entries := pl.EntryCreditBlock.GetEntries() i := 0 // Find the end of the last IncreaseBalance in this minute for i < len(entries) { if _, ok := entries[i].(*entryCreditBlock.IncreaseBalance); ok { break } i++ } entries = append(entries, nil) copy(entries[i+1:], entries[i:]) entries[i] = incBal pl.EntryCreditBlock.GetBody().SetEntries(entries) } } return nil }
func (w *SCWallet) AddInput(trans interfaces.ITransaction, address interfaces.IAddress, amount uint64) error { // Check if this is an address we know. we, adr, err := w.getWalletEntry([]byte(constants.W_RCD_ADDRESS_HASH), address) // If it isn't, we assume the user knows what they are doing. if we == nil || err != nil { rcd := NewRCD_1(address.Bytes()) trans.AddRCD(rcd) adr, err := rcd.GetAddress() if err != nil { return err } trans.AddInput(CreateAddress(adr), amount) } else { trans.AddRCD(we.GetRCD()) trans.AddInput(CreateAddress(adr), amount) } return nil }
// Add the first transaction of a block. This transaction makes the // payout to the servers, so it has no inputs. This transaction must // be deterministic so that all servers will know and expect its output. func (b *FBlock) AddCoinbase(trans interfaces.ITransaction) error { b.BodyMR = nil if len(b.Transactions) != 0 { return fmt.Errorf("The coinbase transaction must be the first transaction") } if len(trans.GetInputs()) != 0 { return fmt.Errorf("The coinbase transaction cannot have any inputs") } if len(trans.GetECOutputs()) != 0 { return fmt.Errorf("The coinbase transaction cannot buy Entry Credits") } if len(trans.GetRCDs()) != 0 { return fmt.Errorf("The coinbase transaction cannot have anyRCD blocks") } if len(trans.GetSignatureBlocks()) != 0 { return fmt.Errorf("The coinbase transaction is not signed") } // TODO Add check here for the proper payouts. b.Transactions = append(b.Transactions, trans) return nil }
func (w *SCWallet) SignInputs(trans interfaces.ITransaction) (bool, error) { data, err := trans.MarshalBinarySig() // Get the part of the transaction we sign if err != nil { return false, err } var numSigs int = 0 inputs := trans.GetInputs() rcds := trans.GetRCDs() for i, rcd := range rcds { rcd1, ok := rcd.(*RCD_1) if ok { pub := rcd1.GetPublicKey() wex, err := w.db.Get([]byte(constants.W_ADDRESS_PUB_KEY), pub, new(WalletEntry)) if err != nil { return false, err } we := wex.(*WalletEntry) if we != nil { var pri [constants.SIGNATURE_LENGTH]byte copy(pri[:], we.private[0]) bsig := ed25519.Sign(&pri, data) sig := new(FactoidSignature) sig.SetSignature(bsig[:]) sigblk := new(SignatureBlock) sigblk.AddSignature(sig) trans.SetSignatureBlock(i, sigblk) numSigs += 1 } } } return numSigs == len(inputs), nil }
// Assumes validation has already been done. func (fs *FactoidState) UpdateTransaction(rt bool, trans interfaces.ITransaction) error { for _, input := range trans.GetInputs() { adr := input.GetAddress().Fixed() oldv := fs.State.GetF(rt, adr) fs.State.PutF(rt, adr, oldv-int64(input.GetAmount())) } for _, output := range trans.GetOutputs() { adr := output.GetAddress().Fixed() oldv := fs.State.GetF(rt, adr) fs.State.PutF(rt, adr, oldv+int64(output.GetAmount())) } for _, ecOut := range trans.GetECOutputs() { ecbal := int64(ecOut.GetAmount()) / int64(fs.State.FactoshisPerEC) fs.State.PutE(rt, ecOut.GetAddress().Fixed(), fs.State.GetE(rt, ecOut.GetAddress().Fixed())+ecbal) } fs.State.NumTransactions++ return nil }
func (w *SCWallet) ValidateSignatures(trans interfaces.ITransaction) error { if trans == nil { return fmt.Errorf("Missing Transaction") } return trans.ValidateSignatures() }
func (w *SCWallet) Validate(index int, trans interfaces.ITransaction) error { err := trans.Validate(index) return err }
func (b FBlock) ValidateTransaction(index int, trans interfaces.ITransaction) error { // Calculate the fee due. { err := trans.Validate(index) if err != nil { return err } } //Ignore coinbase transaction's signatures if len(b.Transactions) > 0 { err := trans.ValidateSignatures() if err != nil { return err } } fee, err := trans.CalculateFee(b.ExchRate) if err != nil { return err } tin, err := trans.TotalInputs() if err != nil { return err } tout, err := trans.TotalOutputs() if err != nil { return err } tec, err := trans.TotalECs() if err != nil { return err } sum, err := ValidateAmounts(tout, tec, fee) if err != nil { return err } if tin < sum { return fmt.Errorf("The inputs %s do not cover the outputs %s,\n"+ "the Entry Credit outputs %s, and the required fee %s", primitives.ConvertDecimalToString(tin), primitives.ConvertDecimalToString(tout), primitives.ConvertDecimalToString(tec), primitives.ConvertDecimalToString(fee)) } return nil }