5. Tranzacții

Spread the love

Fiecare tranzacție presupune transmiterea unor informații:

1. Cheia publică (adresa) a portofelului care transmite fondurile
2. Cheia publică (adresa) a portofelului care primește fondurile
3. Valoarea fondurilor ce urmează a fi transferate
4. Informații = referințe la tranzacțiile precedente care să demonstreze ca cel care trimite are fondurile respective la dispoziție
5. Informațiile privind tranzacția care cor fi folosite la tranzacțiile viitoare (referințele de la punctul 4)
6. O semnătură criptografica care atestă că deținătorul cheii publice este cel care inițiază tranzacția și nu altcineva. De asemnea prin semnătură ne asigurăm că datele nu au fost modificate de la semnare. (reamintesc ca se folosește o pereche de chei publică – privat, am explicat anterior cum se fac aceste verificări)

Ținând seama de cele de mai sus, vom crea o clasă nouă = Tranzactie.  Pentru punctie 4 si 5 va trebuie sa adaugăm 2 noi clase: TranzactieInput și TranzacțieOutput.

Să le luăm pe rând – intâi TranzactieInput si TrnzactieOutput – momentan vor fi niște clase goale – vom vedea mai târziu ce vom scrie în ele:

 
class TranzactieInput {
    
}
class TranzactieOutput {
    
}

Să începem să construim clasa Tranzactie:

 
public class Tranzactie {
	
	public String transactionId; // acesta va fi si hash-ul tranzactiei = identificatorul ei unic
	public PublicKey sender; // cheia publica a portofelului care transmite fondurile
	public PublicKey reciepient; // Recipients address/public key.
	public float value;//valoare fondurilor
	public byte[] signature; // semnatura tranzactiei
	
	public ArrayList inputs = new ArrayList();//referintele de la tranzactiile anterioare
	public ArrayList outputs = new ArrayList();//referintele de la actuala tranzactie care vor fi folosite la viitoarele tranzactii
	
	private static int sequence = 0; // numarul de tranzactii care vor fi generate 

Vom adăuga si un constructor

 
// Constructor: 
public Tranzactie(PublicKey from, PublicKey to, float value,  ArrayList inputs) {
	this.sender = from;
	this.reciepient = to;
	this.value = value;
	this.inputs = inputs;
}

Pentru fiecare tranzacție vom calcula un hash care va trebui să fie unic. Vom folosi 2 funcții – una care există deja in clasa Utile – applySha256 si una nouă – getStringfromKey pentru a obtine un string din cheia publică a celui care transmite fonsurile, respectiv cel care le va primi.

Deci in clasa Utile adăugăm

 
    public static String getStringFromKey(Key key) {
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }

iar în clasa Tranzacție funcția de calculare a hash-ului (modficati funcția applySha256 să fie public în clasa Utile dacă n-o aveți deja așa):

 
	private String calulateHash() {
		sequence++; //Incrementam secventa pentru a nu avea 2 tranzactii cu acelasi hash
		return Utile.applySha256(
				Utile.getStringFromKey(sender) +
				Utile.getStringFromKey(reciepient) +
				Float.toString(value) + sequence
				);
	}

În Utile vom mai avea nevoie de 2 funcții – una care sa întparcă o semnătură și alta care să verifice semnătura:

 
    //Intoarce o semnatura ECDSA sub forma unui array de bytes
    public static byte[] applyECDSASig(PrivateKey privateKey, String input) {
        Signature dsa;
        byte[] output = new byte[0];
        try {
            dsa = Signature.getInstance("ECDSA", "BC");
            dsa.initSign(privateKey);
            byte[] strByte = input.getBytes();
            dsa.update(strByte);
            byte[] realSig = dsa.sign();
            output = realSig;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return output;
    }

    //Verifica semnatura
    public static boolean verifyECDSASig(PublicKey publicKey, String data, byte[] signature) {
        try {
            Signature ecdsaVerify = Signature.getInstance("ECDSA", "BC");
            ecdsaVerify.initVerify(publicKey);
            ecdsaVerify.update(data.getBytes());
            return ecdsaVerify.verify(signature);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

Și acum folosim cele 2 funcții în clasa Tranzactie

 
    //Semnam datele tranzactiei
    public void generateSignature(PrivateKey privateKey) {
        String data = Utile.getStringFromKey(sender) + Utile.getStringFromKey(reciepient) + Float.toString(value);
        signature = Utile.applyECDSASig(privateKey, data);
    }
    //Verificam datele tranzactie
    public boolean verifiySignature() {
        String data = Utile.getStringFromKey(sender) + Utile.getStringFromKey(reciepient) + Float.toString(value);
        return Utile.verifyECDSASig(sender, data, signature);
    }

Pentru a vedea dacă până acum am făcut ce trebuia, vom modifica funcția main ca să testăm noile funcționalități:

 
        Wallet walletA = new Wallet();
        Wallet walletB = new Wallet();
        //testam cheia publica si cea privata
        System.out.println("Cheia privata si cea publica de la portofelul A:");
        System.out.println(Utile.getStringFromKey(walletA.privateKey));
        System.out.println(Utile.getStringFromKey(walletA.publicKey));
        //Create a test transaction from WalletA to walletB 
        Tranzactie transaction = new Tranzactie(walletA.publicKey, walletB.publicKey, 5, null);
        transaction.generateSignature(walletA.privateKey);
        //Verificam semnatura
        System.out.println("Semnatura este verificata ");
        System.out.println(transaction.verifiySignature());

Ar trebui să se afișeze un mesaj de forma (am eliminat System.out din constructorul de la Wallet):

Cheia privata si cea publica de la portofelul A:
MHsCAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEEYTBfAgEBBBi9MfoIZxWU07kfsrxjhixalwOSb09Y8aqgCgYIKoZIzj0DAQGhNAMyAAQEqbr0jsrPqwKLz201ximiz+zuDx+kOlEbQyXlzFANl+aUmDyMOD9ErECzsZwVHHU=
MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEBKm69I7Kz6sCi89tNcYpos/s7g8fpDpRG0Ml5cxQDZfmlJg8jDg/RKxAs7GcFRx1
Semnatura este verificata
true

Dar încă nu am reușit sa efectuăm o tranzacție – continuarea este aici

6. Tranzactii (2)

Comentariile nu sunt permise.