Example #1
0
// 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
}
Example #2
0
func ValidationServiceLoop(input chan ValidationMsg) {
	type ValidationState struct {
		NumTransactions int
		FactoidBalances map[[32]byte]int64
		ECBalances      map[[32]byte]int64
		FactoshisPerEC  uint64
	}

	vs := new(ValidationState)
	vs.FactoshisPerEC = 1
	vs.FactoidBalances = map[[32]byte]int64{}
	vs.ECBalances = map[[32]byte]int64{}

	for {
		msg := <-input
		switch msg.MessageType {
		case MessageTypeGetFactoidBalance:
			v := vs.FactoidBalances[msg.Address]
			if msg.ReturnChannel != nil {
				var resp ValidationResponseMsg
				resp.Balance = v
				msg.ReturnChannel <- resp
			}
			break

		case MessageTypeGetECBalance:
			v := vs.ECBalances[msg.Address]
			if msg.ReturnChannel != nil {
				var resp ValidationResponseMsg
				resp.Balance = v
				msg.ReturnChannel <- resp
			}
			break

		case MessageTypeUpdateTransaction:

			if msg.Transaction == nil && msg.ECTransaction == nil {
				if msg.ReturnChannel != nil {
					var resp ValidationResponseMsg
					resp.Error = fmt.Errorf("No transaction provided")
					msg.ReturnChannel <- resp
				}
				break
			}

			if msg.Transaction != nil {
				trans := msg.Transaction
				for _, input := range trans.GetInputs() {
					vs.FactoidBalances[input.GetAddress().Fixed()] = vs.FactoidBalances[input.GetAddress().Fixed()] - int64(input.GetAmount())
				}
				for _, output := range trans.GetOutputs() {
					vs.FactoidBalances[output.GetAddress().Fixed()] = vs.FactoidBalances[output.GetAddress().Fixed()] + int64(output.GetAmount())
				}
				for _, ecOut := range trans.GetECOutputs() {
					ecbal := int64(ecOut.GetAmount()) / int64(vs.FactoshisPerEC)
					vs.ECBalances[ecOut.GetAddress().Fixed()] = vs.ECBalances[ecOut.GetAddress().Fixed()] + ecbal
				}
				vs.NumTransactions++
				if msg.ReturnChannel != nil {
					var resp ValidationResponseMsg
					msg.ReturnChannel <- resp
				}
			}

			if msg.ECTransaction != nil {
				trans := msg.ECTransaction
				var resp ValidationResponseMsg

				switch trans.ECID() {
				case entryCreditBlock.ECIDServerIndexNumber:
					resp.Error = fmt.Errorf("Invalid transaction provided")
					msg.ReturnChannel <- resp
					break

				case entryCreditBlock.ECIDMinuteNumber:
					resp.Error = fmt.Errorf("Invalid transaction provided")
					msg.ReturnChannel <- resp
					break

				case entryCreditBlock.ECIDChainCommit:
					t := trans.(*entryCreditBlock.CommitChain)
					vs.ECBalances[t.ECPubKey.Fixed()] = vs.ECBalances[t.ECPubKey.Fixed()] - int64(t.Credits)
					vs.NumTransactions++
					msg.ReturnChannel <- resp
					break

				case entryCreditBlock.ECIDEntryCommit:
					t := trans.(*entryCreditBlock.CommitEntry)
					vs.ECBalances[t.ECPubKey.Fixed()] = vs.ECBalances[t.ECPubKey.Fixed()] - int64(t.Credits)
					vs.NumTransactions++

					msg.ReturnChannel <- resp
					break

				case entryCreditBlock.ECIDBalanceIncrease:
					t := trans.(*entryCreditBlock.IncreaseBalance)
					vs.ECBalances[t.ECPubKey.Fixed()] = vs.ECBalances[t.ECPubKey.Fixed()] + int64(t.NumEC)
					vs.NumTransactions++

					msg.ReturnChannel <- resp
					break

				default:
					resp.Error = fmt.Errorf("Unknown EC transaction provided")
					msg.ReturnChannel <- resp
					break
				}
			}

			break

		case MessageTypeResetBalances:
			vs.FactoidBalances = map[[32]byte]int64{}
			vs.ECBalances = map[[32]byte]int64{}
			vs.NumTransactions = 0
			break

		case MessageTypeGetFactoshisPerEC:
			if msg.ReturnChannel != nil {
				var resp ValidationResponseMsg
				resp.FactoshisPerEC = vs.FactoshisPerEC
				msg.ReturnChannel <- resp
			}
			break

		case MessageTypeSetFactoshisPerEC:
			vs.FactoshisPerEC = msg.FactoshisPerEC
			if msg.ReturnChannel != nil {
				var resp ValidationResponseMsg
				msg.ReturnChannel <- resp
			}
			break

		case MessageTypeValidate:
			var resp ValidationResponseMsg
			var sums = make(map[[32]byte]uint64, 10) // Look at the sum of an address's inputs
			trans := msg.Transaction
			for _, input := range trans.GetInputs() { //    to a transaction.
				bal, err := factoid.ValidateAmounts(sums[input.GetAddress().Fixed()], input.GetAmount())
				if err != nil {
					if msg.ReturnChannel != nil {
						resp.Error = err
						msg.ReturnChannel <- resp
					}
					break
				}
				if int64(bal) > vs.FactoidBalances[input.GetAddress().Fixed()] {
					if msg.ReturnChannel != nil {
						resp.Error = fmt.Errorf("Not enough funds in input addresses for the transaction")
						msg.ReturnChannel <- resp
					}
					break
				}
				sums[input.GetAddress().Fixed()] = bal
			}
			msg.ReturnChannel <- resp
			break

		default:
			if msg.ReturnChannel != nil {
				var resp ValidationResponseMsg
				resp.Error = fmt.Errorf("Unknown MessageType")
				msg.ReturnChannel <- resp
			}
		}
	}
}