package jstellarapi.serialization;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import jstellarapi.keys.StellarDeterministicKeyGenerator;
import jstellarapi.serialization.StellarBinarySchema.BinaryFormatField;
import jstellarapi.serialization.StellarBinarySchema.PrimitiveTypes;
import jstellarapi.serialization.StellarBinarySchema.TransactionTypes;
import org.json.simple.JSONObject;
public class StellarBinaryObject {
HashMap<BinaryFormatField, Object> fields = new HashMap<BinaryFormatField, Object>();
static StellarBinarySerializer binSer=new StellarBinarySerializer();
public StellarBinaryObject(){
}
public StellarBinaryObject(StellarBinaryObject serObjToSign) {
this.fields.putAll(serObjToSign.fields);
}
public StellarBinaryObject getUnsignedCopy(){
StellarBinaryObject copy = new StellarBinaryObject(this);
copy.removeField(BinaryFormatField.TxnSignature);
return copy;
}
public byte[] generateHashFromBinaryObject() {
byte[] bytesToSign = binSer.writeBinaryObject(this).array();
//Prefix bytesToSign with the magic hashing prefix (32bit) 'STX\0'
byte[] prefixedBytesToHash = new byte[bytesToSign.length+4];
prefixedBytesToHash[0]=(byte) 'S';
prefixedBytesToHash[1]=(byte) 'T';
prefixedBytesToHash[2]=(byte) 'X';
prefixedBytesToHash[3]=(byte) 0;
System.arraycopy(bytesToSign, 0, prefixedBytesToHash, 4, bytesToSign.length);
//Hash256
byte[] hashOfBytes = StellarDeterministicKeyGenerator.halfSHA512(prefixedBytesToHash);
return hashOfBytes;
}
public byte[] getTransactionHash(){
//Convert to bytes again
byte[] signedBytes = binSer.writeBinaryObject(this).array();
//Prefix bytesToSign with the magic sigining prefix (32bit) 'TXN\0'
byte[] prefixedSignedBytes = new byte[signedBytes.length+4];
prefixedSignedBytes[0]=(byte) 'T';
prefixedSignedBytes[1]=(byte) 'X';
prefixedSignedBytes[2]=(byte) 'N';
prefixedSignedBytes[3]=(byte) 0;
System.arraycopy(signedBytes, 0, prefixedSignedBytes, 4, signedBytes.length);
//Hash again, this wields the TransactionID
byte[] hashOfTransaction = StellarDeterministicKeyGenerator.halfSHA512(prefixedSignedBytes);
return hashOfTransaction;
}
public Object getField(BinaryFormatField transactiontype) {
Object obj = fields.get(transactiontype);
if(obj==null){
return null; //TODO refactor with Maybe object?
}
return obj;
}
public void putField(BinaryFormatField field, Object value){
fields.put(field, value);
}
public TransactionTypes getTransactionType() {
Object txTypeObj = getField(BinaryFormatField.TransactionType);
if(txTypeObj==null){
throw new NullPointerException("No transaction type field found");
}
return TransactionTypes.fromType((int) txTypeObj);
}
public String toJSONString() {
JSONObject root = new JSONObject();
for(Entry<BinaryFormatField, Object> field:fields.entrySet()){
PrimitiveTypes primitive = field.getKey().primitive;
if(primitive==PrimitiveTypes.UINT8 || primitive==PrimitiveTypes.UINT16
|| primitive==PrimitiveTypes.UINT32 || primitive==PrimitiveTypes.UINT64){
root.put(field.getKey().toString(), field.getValue());
}
else{
root.put(field.getKey().toString(), field.getValue().toString());
}
}
return root.toJSONString();
}
public List<BinaryFormatField> getSortedField() {
ArrayList<BinaryFormatField> sortedFields = new ArrayList<BinaryFormatField>(fields.keySet());
Collections.sort(sortedFields);
return sortedFields;
}
public Object removeField(BinaryFormatField fieldToBeRemoved) {
return fields.remove(fieldToBeRemoved);
}
@Override
public String toString() {
return "StellarBinaryObject [fields=" + fields + "]";
}
}