6. Tranzactii (2)

Spread the love

La bitcoin și la majoritatea celolalte criptomonede o persoană nu poți să introduci monede noi decât dacă primești de la un alt portofel (doar minerii adaugă monede noi în sistem).
Ca urmare, pentru a avea 1 monedă, trebuie ca cineva să-ți fi transmis printr-o tranzacție 1 monedă. Astfel totalul monedelor din portofelul tău va consta in toate unitățile primite și necheltuite. (netransmise altcuiva). Vom respecta terminologia de la bitcoin si vom denumi aceste unități de tranzacționare  necheltuite UTXO.

Să completăm mai întâi clasa TranzactieInput:

  
class TranzactieInput {

    public String tranzactieOutputId; //Referinta la TranzactieOutput -> tranzactieId
    public TranzactieOutput UTXO; //contine suma de unitati necheltuite (suma de monede detinuta de portofel)

    public TranzactieInput(String tranzactieOutputId) {
        this.tranzactieOutputId = tranzactieOutputId;
    }
}

The tranzactieOutputId va fi folosit penru identificarea obiectului TranzactieOutput, permitând astfel minerilor sa verifice dacă îți aparține sau nu.

Ne vom ocupa acum si de TranzactieOutput:

  
class TranzactieOutput {

    public String id;
    public PublicKey reciepient; //cui trimitem monedele prin tranzactie.
    public float value; //suma transmisa
    public String parentTransactionId; //id-ul tranzacriei  in interiorul careia s-a creat noul output

    //Constructor
    public TranzactieOutput(PublicKey reciepient, float value, String parentTransactionId) {
        this.reciepient = reciepient;
        this.value = value;
        this.parentTransactionId = parentTransactionId;
        this.id = Utile.applySha256(Utile.getStringFromKey(reciepient) + Float.toString(value) + parentTransactionId);
    }

    //verifica daca monedele iti apartin
    public boolean isMine(PublicKey publicKey) {
        return (publicKey == reciepient);
    }
}

Output-ul de la tranzacții arată suma care este transmisă. Aceasta va apare ca referință într=o nouă tranzacție, pentru a se putea verfica că exista fondurile necesare pentru noua tranzacție.

Într-un lanț de tip blockchain pot exista o mulțime de tranzacții și procesul de verificare care ar trebui să verifice toate tranzacțiile anterioare care au o referință (directă sau în mai mulți pași) cu tranzacția curentă poate fi foarte, foarte lung. Vom păstra o colecție cu toate monedele care pot fi cheltuite – vom crea într-o nouă clasă (DeCheltuit) o colecție de UTXO:

  
public class DeCheltuit {
    public static HashMap<String,TranzactieOutput> UTXOs = new HashMap<String,TranzactieOutput>(); //lista tuturor sumelor care pot fi transferate (cheltuite) 
    public static float valoareMinima=0.01f;// valoarea minima a unei tranzactii
}

Am ajuns la realizarea unei tranzacții…Vom adăuga o metodă = procesareTranzacție în care vom efectua operațiile necesare:

  
 public boolean procesareTranzactie() {
		
		if(verifiySignature() == false) {
			System.out.println("#Semnatura tranzactiei nu a putut fi verificata");
			return false;
		}
				
		//obtine intrarile tranzactiilor (necheltuite)
		for(TranzactieInput i : inputs) {
			i.UTXO = DeCheltuit.UTXOs.get(i.tranzactieOutputId);
		}

		//verifica daca tranzactia este valida:
		if(getInputsValue() < DeCheltuit.valoareMinima) {
			System.out.println("#Transaction Inputs to small: " + getInputsValue());
			return false;
		}
		
		//genereaza iesirile tranzactiei:
		float leftOver = getInputsValue() - value; //obtine valoarea intrarilor 
		transactionId = calulateHash();
		outputs.add(new TranzactieOutput( this.reciepient, value,transactionId)); //trimite valoarea destinatarului
		outputs.add(new TranzactieOutput( this.sender, leftOver,transactionId)); //trimite valoarea ramasa expeditorului	
				
		//adaugam iesirile la lista cu ce este necheltuit
		for(TranzactieOutput o : outputs) {
			DeCheltuit.UTXOs.put(o.id , o);
		}
		
		//elimina intrarile de tranzactii din lista
		for(TranzactieInput i : inputs) {
			if(i.UTXO == null) continue; //daca tranzactia nu poate fi gasita, trecem mai departe
			DeCheltuit.UTXOs.remove(i.UTXO.id);
		}
		
		return true;
	}
	
//returneaza suma intrarilor
	public float getInputsValue() {
		float total = 0;
		for(TranzactieInput i : inputs) {
			if(i.UTXO == null) continue; //daca tranzactia nu poate fi gasita, trecem mai departe
			total += i.UTXO.value;
		}
		return total;
	}

//returneaza suma iesirilor
	public float getOutputsValue() {
		float total = 0;
		for(TranzactieOutput o : outputs) {
			total += o.value;
		}
		return total;
}

Se observa ca in final eliminam intrari de tranzactii din lista noastra (pe principiul ca o ieisre nu poate fi folosita decat o singura data ca intrare)

Mai este necesară și modificarea clasei Wallet, astfel încât:

  • Să obținem balanța finală a portofelului ( trecând prin lista de UTXO si verificând care sunt ale mele = isMine())
  • Generăm tranzacția
  
    public float getBalance() {
        float total = 0;
        for (Map.Entry<String, TranzactieOutput> item : DeCheltuit.UTXOs.entrySet()) {
            TranzactieOutput UTXO = item.getValue();
            if (UTXO.isMine(publicKey)) { //daca iesirea imi partine
                UTXOs.put(UTXO.id, UTXO); //o adaugam la lista fondurilor necheltuite
                total += UTXO.value;
            }
        }
        return total;
    }

    //Genreaza si returneaza o tranzactie 
    public Tranzactie sendFunds(PublicKey _recipient, float value) {
        if (getBalance() < value) { //obtinem balanta si verificam fondurile disponibile
            System.out.println("#Nu aveti destule fonduri. Tranzactie anulata.");
            return null;
        }
        //cream o lista de intrari
        ArrayList inputs = new ArrayList();

        float total = 0;
        for (Map.Entry<String, TranzactieOutput> item : UTXOs.entrySet()) {
            TranzactieOutput UTXO = item.getValue();
            total += UTXO.value;
            inputs.add(new TranzactieInput(UTXO.id));
            if (total > value) {
                break;
            }
        }

        Tranzactie newTransaction = new Tranzactie(publicKey, _recipient, value, inputs);
        newTransaction.generateSignature(privateKey);

        for (TranzactieInput input : inputs) {
            UTXOs.remove(input.tranzactieOutputId);
        }
        return newTransaction;
    }

Și tot nu am terminat – trebuie să mai adăugăm tranzacția la blocul nostru și in final sa facem un test – să vedem cum se realizează tranzacția. Dara asta rămâne să facem în următoarea parte – Tranzactii(3)

Comentariile nu sunt permise.