Beispiel #1
0
func (b *FBlock) MarshalTrans() ([]byte, error) {
	var out bytes.Buffer
	var periodMark = 0
	var i int
	var trans fct.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(fct.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(fct.MARKER)
		periodMark++
	}
	return out.Bytes(), nil
}
Beispiel #2
0
func FactoidAddOutput(trans fct.ITransaction, key string, address fct.IAddress, amount uint64) error {
	ok := Utility.IsValidKey(key)
	if !ok {
		return fmt.Errorf("Invalid name for transaction")
	}

	// First look if this is really an update
	for _, output := range trans.GetOutputs() {
		if output.GetAddress().IsSameAs(address) {
			output.SetAmount(amount)
			return nil
		}
	}
	// Add our new Output
	err := factoidState.GetWallet().AddOutput(trans, address, uint64(amount))
	if err != nil {
		return fmt.Errorf("Failed to add output")
	}

	// Update our map with our new transaction to the same key.  Otherwise, all
	// of our work will go away!
	factoidState.GetDB().PutRaw([]byte(fct.DB_BUILD_TRANS), []byte(key), trans)

	return nil
}
Beispiel #3
0
func HandleGetFee(ctx *web.Context, k string) {

	var trans fct.ITransaction
	var err error

	key := ctx.Params["key"]

	fmt.Println("getfee", key)

	if len(key) > 0 {
		trans, err = getTransaction(ctx, key)
		if err != nil {
			reportResults(ctx, "Failure to locate the transaction", false)
			return
		}
	}

	fee, err := Wallet.GetFee()
	if err != nil {
		reportResults(ctx, err.Error(), false)
		return
	}

	if trans != nil {
		ufee, _ := trans.CalculateFee(uint64(fee))
		fee = int64(ufee)
	}

	reportResults(ctx, fmt.Sprintf("%s", strings.TrimSpace(fct.ConvertDecimal(uint64(fee)))), true)
}
Beispiel #4
0
func (w *SCWallet) AddECOutput(trans fct.ITransaction, address fct.IAddress, amount uint64) error {

	_, adr, err := w.getWalletEntry([]byte(fct.W_RCD_ADDRESS_HASH), address)
	if err != nil {
		adr = address
	}

	trans.AddECOutput(fct.CreateAddress(adr), amount)
	return nil
}
Beispiel #5
0
func FactoidAddFee(trans fct.ITransaction, key string, address fct.IAddress, name string) (uint64, error) {
	{
		ins, err := trans.TotalInputs()
		if err != nil {
			return 0, err
		}
		outs, err := trans.TotalOutputs()
		if err != nil {
			return 0, err
		}
		ecs, err := trans.TotalECs()
		if err != nil {
			return 0, err
		}

		if ins != outs+ecs {
			return 0, fmt.Errorf("Inputs and outputs don't add up")
		}
	}

	ok := Utility.IsValidKey(key)
	if !ok {
		return 0, fmt.Errorf("Invalid name for transaction")
	}

	fee, err := GetFee()
	if err != nil {
		return 0, err
	}

	transfee, err := trans.CalculateFee(uint64(fee))
	if err != nil {
		return 0, err
	}

	adr, err := factoidState.GetWallet().GetAddressHash(address)
	if err != nil {
		return 0, err
	}

	for _, input := range trans.GetInputs() {
		if input.GetAddress().IsSameAs(adr) {
			amt, err := fct.ValidateAmounts(input.GetAmount(), transfee)
			if err != nil {
				return 0, err
			}
			input.SetAmount(amt)
			return transfee, nil
		}
	}
	return 0, fmt.Errorf("%s is not an input to the transaction.", key)
}
Beispiel #6
0
func (w *SCWallet) SignInputs(trans fct.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.(*fct.RCD_1)
		if ok {
			pub := rcd1.GetPublicKey()
			we := w.db.GetRaw([]byte(fct.W_ADDRESS_PUB_KEY), pub).(*WalletEntry)
			if we != nil {
				var pri [fct.SIGNATURE_LENGTH]byte
				copy(pri[:], we.private[0])
				bsig := ed25519.Sign(&pri, data)
				sig := new(fct.Signature)
				sig.SetSignature(bsig[:])
				sigblk := new(fct.SignatureBlock)
				sigblk.AddSignature(sig)
				trans.SetSignatureBlock(i, sigblk)
				numSigs += 1
			}
		}
	}

	return numSigs == len(inputs), nil
}
Beispiel #7
0
// FactoidSubmit assumes the caller has already validated and signed
// the transaction.  No checking is done, it is just submitted to Factom.
func FactoidSubmit(trans fct.ITransaction) (err error) {

	var data []byte
	if data, err = trans.MarshalBinary(); err != nil {
		return err
	}

	transdata := string(hex.EncodeToString(data))

	s := struct{ Transaction string }{transdata}

	var js []byte
	if js, err = json.Marshal(s); err != nil {
		return err
	}

	resp, err := http.Post(
		fmt.Sprintf("http://%s/v1/factoid-submit/", ipaddressFD+portNumberFD),
		"application/json",
		bytes.NewBuffer(js))

	if err != nil {
		return err
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	resp.Body.Close()

	type rtnStruct struct {
		Response string
		Success  bool
	}
	rtn := new(rtnStruct)
	if err := json.Unmarshal(body, rtn); err != nil {
		return err
	}

	if !rtn.Success {
		return fmt.Errorf(rtn.Response)
	}

	return nil
}
Beispiel #8
0
// Checks the transaction timestamp for validity in being included in the current block.
// 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 fct.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 > fct.TRANSACTION_PRIOR_LIMIT {
		return fmt.Errorf("Transaction is too old to be included in the current block")
	}

	if tstrans-tsblk > fct.TRANSACTION_POST_LIMIT {
		return fmt.Errorf("Transaction is dated too far in the future to be included in the current block")
	}
	return nil
}
Beispiel #9
0
// Assumes validation has already been done.
func (fs *AssetState) UpdateTransaction(trans fct.ITransaction) error {
	for _, input := range trans.GetInputs() {
		fs.UpdateBalance(input.GetAddress(), -int64(input.GetAmount()))
	}
	for _, output := range trans.GetOutputs() {
		fs.UpdateBalance(output.GetAddress(), int64(output.GetAmount()))
	}

	fs.numTransactions++
	cp.CP.AddUpdate(
		"transprocessed", // tag
		"status",         // Category
		fmt.Sprintf("Factoid Transactions Processed: %d", fs.numTransactions), // Title
		"", // Message
		0)  // When to expire the message; 0 is never

	return nil
}
Beispiel #10
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 fct.ITransaction) error {
	err := fs.currentBlock.ValidateTransaction(index, trans)
	if err != nil {
		return err
	}

	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 := fct.ValidateAmounts(sums[input.GetAddress().Fixed()], input.GetAmount())
		if err != nil {
			return err
		}
		if bal > fs.GetBalance(input.GetAddress()) {
			return fmt.Errorf("Not enough funds in input addresses for the transaction")
		}
		sums[input.GetAddress().Fixed()] = bal
	}
	return nil
}
Beispiel #11
0
func (w *SCWallet) UpdateInput(trans fct.ITransaction, index int, address fct.IAddress, amount uint64) error {

	we, adr, err := w.getWalletEntry([]byte(fct.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
}
Beispiel #12
0
// Returns an error message about what is wrong with the transaction if it is
// invalid, otherwise you are good to go.
func (fs *AssetState) Validate(trans fct.ITransaction) error {

	if err := trans.ValidateSignatures(); err != nil {
		return err
	}

	var sums = make(map[fct.IAddress]uint64, 10)
	for _, input := range trans.GetInputs() {
		bal, err := fct.ValidateAmounts(
			sums[input.GetAddress()], // Will be zero the first time around
			input.GetAmount())        // Get this amount, check against bounds
		if err != nil {
			return err
		}
		if bal > fs.GetBalance(input.GetAddress()) {
			return fmt.Errorf("Not enough funds in input addresses for the transaction")
		}
		sums[input.GetAddress()] = bal
	}
	return nil
}
Beispiel #13
0
func (w *SCWallet) AddInput(trans fct.ITransaction, address fct.IAddress, amount uint64) error {
	// Check if this is an address we know.
	we, adr, err := w.getWalletEntry([]byte(fct.W_RCD_ADDRESS_HASH), address)
	// If it isn't, we assume the user knows what they are doing.
	if we == nil || err != nil {
		rcd := fct.NewRCD_1(address.Bytes())
		trans.AddRCD(rcd)
		adr, err := rcd.GetAddress()
		if err != nil {
			return err
		}
		trans.AddInput(fct.CreateAddress(adr), amount)
	} else {
		trans.AddRCD(we.GetRCD())
		trans.AddInput(fct.CreateAddress(adr), amount)
	}

	return nil
}
Beispiel #14
0
func PrtTrans(t fct.ITransaction) {
	fmt.Println("Transaction")
	for _, input := range t.GetInputs() {
		fmt.Println("in ", input.GetAddress(), input.GetAmount(), fs.GetBalance(input.GetAddress()))
	}
	for _, output := range t.GetOutputs() {
		fmt.Println("out", output.GetAddress(), output.GetAmount(), fs.GetBalance(output.GetAddress()))
	}
	for _, ecoutput := range t.GetECOutputs() {
		fmt.Println("ec ", ecoutput.GetAddress(), ecoutput.GetAmount(), fs.GetECBalance(ecoutput.GetAddress()))
	}
}
Beispiel #15
0
func isReasonableFee(trans fct.ITransaction) error {
	feeRate, getErr := GetFee()
	if getErr != nil {
		return getErr
	}

	reqFee, err := trans.CalculateFee(uint64(feeRate))
	if err != nil {
		return err
	}

	sreqFee := int64(reqFee)

	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
	}

	cfee := int64(tin) - int64(tout) - int64(tec)

	if cfee >= (sreqFee * 10) {
		return fmt.Errorf("Unbalanced transaction (fee too high). Fee should be less than 10x the required fee.")
	}

	if cfee < sreqFee {
		return fmt.Errorf("Insufficient fee")
	}

	return nil
}
Beispiel #16
0
// 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 fct.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
}
Beispiel #17
0
func (w *SCWallet) SignInputs(trans fct.ITransaction) (bool, error) {

	data, err := trans.MarshalBinarySig() // Get the part of the transaction we sign
	if err != nil {
		return false, err
	}

	var errMsg []byte

	rcds := trans.GetRCDs()
	for i, rcd := range rcds {
		rcd1, ok := rcd.(*fct.RCD_1)
		if ok {
			pub := rcd1.GetPublicKey()
			we, ok := w.db.GetRaw([]byte(fct.W_ADDRESS_PUB_KEY), pub).(*WalletEntry)
			if ok {
				var pri [fct.SIGNATURE_LENGTH]byte
				copy(pri[:], we.private[0])
				bsig := ed25519.Sign(&pri, data)
				sig := new(fct.Signature)
				sig.SetSignature(bsig[:])
				sigblk := new(fct.SignatureBlock)
				sigblk.AddSignature(sig)
				trans.SetSignatureBlock(i, sigblk)
			} else {
				errMsg = append(errMsg,
					[]byte("Do not have the private key for: "+
						fct.ConvertFctAddressToUserStr(fct.NewAddress(pub))+"\n")...)
			}
		}
	}

	if errMsg != nil {
		return false, fmt.Errorf("%s", string(errMsg))
	}
	return true, nil
}
Beispiel #18
0
func (b FBlock) ValidateTransaction(index int, trans fct.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 := fct.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",
			strings.TrimSpace(fct.ConvertDecimal(tin)),
			strings.TrimSpace(fct.ConvertDecimal(tout)),
			strings.TrimSpace(fct.ConvertDecimal(tec)),
			strings.TrimSpace(fct.ConvertDecimal(fee)))
	}
	return nil
}
Beispiel #19
0
func filtertransaction(trans fct.ITransaction, addresses [][]byte) bool {
	if addresses == nil || len(addresses) == 0 {
		return true
	}
	if len(trans.GetInputs()) == 0 &&
		len(trans.GetOutputs()) == 0 {
		return false
	}

	if len(addresses) == 1 && bytes.Equal(addresses[0], trans.GetSigHash().Bytes()) {
		return true
	}

Search:
	for _, adr := range addresses {

		for _, in := range trans.GetInputs() {
			if bytes.Equal(adr, in.GetAddress().Bytes()) {
				continue Search
			}
		}
		for _, out := range trans.GetOutputs() {
			if bytes.Equal(adr, out.GetAddress().Bytes()) {
				continue Search
			}
		}
		for _, ec := range trans.GetECOutputs() {
			if bytes.Equal(adr, ec.GetAddress().Bytes()) {
				continue Search
			}
		}
		return false
	}
	return true
}
Beispiel #20
0
func (w *SCWallet) ValidateSignatures(trans fct.ITransaction) error {
	if trans == nil {
		return fmt.Errorf("Missing Transaction")
	}
	return trans.ValidateSignatures()
}
Beispiel #21
0
func (w *SCWallet) Validate(index int, trans fct.ITransaction) error {
	err := trans.Validate(index)
	return err
}