Skip to content
This repository was archived by the owner on Jan 8, 2021. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,15 @@
import com.radixdlt.client.application.translate.StatefulActionToParticleGroupsMapper;
import com.radixdlt.client.application.translate.StatelessActionToParticleGroupsMapper;
import com.radixdlt.client.application.translate.data.AtomToDecryptedMessageMapper;
import com.radixdlt.client.application.translate.data.CRUDataUpdate;
import com.radixdlt.client.application.translate.data.AtomToCRUDataUpdateMapper;
import com.radixdlt.client.application.translate.data.CreateCRUDataAction;
import com.radixdlt.client.application.translate.data.CreateDataToParticleGroupsMapper;
import com.radixdlt.client.application.translate.data.DecryptedMessage;
import com.radixdlt.client.application.translate.data.SendMessageAction;
import com.radixdlt.client.application.translate.data.SendMessageToParticleGroupsMapper;
import com.radixdlt.client.application.translate.data.UpdateCRUDataAction;
import com.radixdlt.client.application.translate.data.UpdateCRUDataToParticleGroupsMapper;
import com.radixdlt.client.application.translate.tokens.AtomToTokenTransfersMapper;
import com.radixdlt.client.application.translate.tokens.BurnTokensAction;
import com.radixdlt.client.application.translate.tokens.BurnTokensActionMapper;
Expand Down Expand Up @@ -146,13 +152,16 @@ public static RadixApplicationAPIBuilder defaultBuilder() {
SendMessageAction.class,
new SendMessageToParticleGroupsMapper(ECKeyPair::generateNew)
)
.addStatelessParticlesMapper(CreateCRUDataAction.class, new CreateDataToParticleGroupsMapper())
.addStatelessParticlesMapper(CreateTokenAction.class, new CreateTokenToParticleGroupsMapper())
.addStatelessParticlesMapper(PutUniqueIdAction.class, new PutUniqueIdToParticleGroupsMapper())
.addStatefulParticlesMapper(UpdateCRUDataAction.class, new UpdateCRUDataToParticleGroupsMapper())
.addStatefulParticlesMapper(MintTokensAction.class, new MintTokensActionMapper())
.addStatefulParticlesMapper(BurnTokensAction.class, new BurnTokensActionMapper())
.addStatefulParticlesMapper(TransferTokensAction.class, new TransferTokensToParticleGroupsMapper())
.addReducer(new TokenDefinitionsReducer())
.addReducer(new TokenBalanceReducer())
.addAtomMapper(new AtomToCRUDataUpdateMapper())
.addAtomMapper(new AtomToDecryptedMessageMapper())
.addAtomMapper(new AtomToTokenTransfersMapper())
.addAtomErrorMapper(new AlreadyUsedUniqueIdReasonMapper());
Expand Down Expand Up @@ -435,6 +444,50 @@ public Result sendMessage(RadixAddress toAddress, byte[] data, boolean encrypt)
return execute(sendMessageAction);
}

/**
* Returns a never ending stream of data stored at a given address. The pull()
* method must be called to continually retrieve the latest messages.
*
* @param address the address to retrieve data from
* @return a cold observable of the messages at the given address
*/
public Observable<CRUDataUpdate> observeData(RadixAddress address) {
Objects.requireNonNull(address);
return observeActions(CRUDataUpdate.class, address);
}

/**
* Creates a data resource and stores it.
*
* @param rri the resource which will be associated with this data
* @param data to be storedg
* @return result of the create data action
*/
public Result createData(RRI rri, byte[] data) {
RadixAddress address = getAddress();
if (!rri.getAddress().equals(address)) {
throw new IllegalArgumentException();
}
CreateCRUDataAction createDataAction = CreateCRUDataAction.create(rri, data);
return execute(createDataAction);
}

/**
* Update an existing data resource
*
* @param rri the resource which is associated with this data
* @param data new version of data
* @return result of the send message execution
*/
public Result updateData(RRI rri, byte[] data) {
RadixAddress address = getAddress();
if (!rri.getAddress().equals(address)) {
throw new IllegalArgumentException();
}
UpdateCRUDataAction updateAction = UpdateCRUDataAction.create(rri, data);
return execute(updateAction);
}

/**
* Returns a never ending stream of token transfers stored at the current address.
* pull() must be called to continually retrieve the latest transfers.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* (C) Copyright 2020 Radix DLT Ltd
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the “Software”),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/

package com.radixdlt.client.application.translate.data;

import java.util.List;
import java.util.stream.Collectors;

import com.radixdlt.client.application.identity.RadixIdentity;
import com.radixdlt.client.application.translate.AtomToExecutedActionsMapper;
import com.radixdlt.client.atommodel.cru.CRUDataParticle;
import com.radixdlt.client.core.atoms.Atom;
import com.radixdlt.client.core.atoms.particles.SpunParticle;

import io.reactivex.Observable;

/**
* Maps an atom to some number of CRUDataUpdate
*/
public class AtomToCRUDataUpdateMapper implements AtomToExecutedActionsMapper<CRUDataUpdate> {

@Override
public Class<CRUDataUpdate> actionClass() {
return CRUDataUpdate.class;
}

@Override
public Observable<CRUDataUpdate> map(Atom atom, RadixIdentity identity) {
long timestamp = atom.getTimestamp();
List<CRUDataUpdate> dataUpdates = atom.spunParticles()
.map(SpunParticle::getParticle)
.filter(p -> p instanceof CRUDataParticle)
.map(CRUDataParticle.class::cast)
.map(p -> new CRUDataUpdate(p.getRRI(), p.data(), timestamp, p.euid()))
.collect(Collectors.toList());
return Observable.fromIterable(dataUpdates);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* (C) Copyright 2020 Radix DLT Ltd
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the “Software”),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/

package com.radixdlt.client.application.translate.data;

import com.radixdlt.client.application.translate.StageActionException;
import com.radixdlt.identifiers.RRI;
import java.util.Objects;

public class CRUDataMissingException extends StageActionException {
private final RRI rri;
private final int nRecords;

public CRUDataMissingException(RRI cruDataRri, int nRecords) {
super("Could not find CRU data " + cruDataRri + " to update");
this.rri = cruDataRri;
this.nRecords = nRecords;
}

public RRI rri() {
return this.rri;
}

public int nRecords() {
return this.nRecords;
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof CRUDataMissingException)) {
return false;
}

CRUDataMissingException that = (CRUDataMissingException) obj;
return this.nRecords == that.nRecords && Objects.equals(this.rri, that.rri);
}

@Override
public int hashCode() {
return this.nRecords * 31 + Objects.hashCode(this.rri);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* (C) Copyright 2020 Radix DLT Ltd
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the “Software”),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/

package com.radixdlt.client.application.translate.data;


import java.util.Arrays;
import java.util.Objects;

import com.radixdlt.identifiers.EUID;
import com.radixdlt.identifiers.RRI;
import com.radixdlt.utils.Bytes;

/**
* An application layer object representing some data found on the ledger.
*/
public class CRUDataUpdate {

private final RRI rri;
private final byte[] data;
private final EUID actionId;
private final transient long timestamp;

public CRUDataUpdate(RRI rri, byte[] data, long timestamp, EUID actionId) {
this.rri = rri;
this.data = data;
this.timestamp = timestamp;
this.actionId = actionId;
}

/**
* The unique id for the this update action.
* @return {@link EUID} for the action
*/
public EUID getActionId() {
return this.actionId;
}

/**
* The data from this update action.
* @return the data for the action
*/
public byte[] getData() {
return data;
}

/**
* The timestamp from this update action.
* <p>
* Timestamp is in milliseconds since Unix epoch.
*
* @return the timestamp for the action
*/
public long getTimestamp() {
return timestamp;
}

/**
* The resource identifier for this update action.
* @return the resource identifier for the action
*/
public RRI rri() {
return rri;
}

@Override
public int hashCode() {
return Objects.hash(this.actionId, this.rri)
* 31 + Arrays.hashCode(this.data);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof CRUDataUpdate) {
CRUDataUpdate that = (CRUDataUpdate) obj;
return Objects.equals(this.actionId, that.actionId)
&& Objects.equals(this.rri, that.rri)
&& Arrays.equals(this.data, that.data);
}
return false;
}

@Override
public String toString() {
return timestamp + " " + rri + " " + Bytes.toHexString(data);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* (C) Copyright 2020 Radix DLT Ltd
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the “Software”),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/

package com.radixdlt.client.application.translate.data;

import java.util.Objects;

import com.radixdlt.client.application.translate.Action;
import com.radixdlt.identifiers.RRI;
import com.radixdlt.utils.Bytes;

/**
* An Action object which create a CRU data object.
*/
public final class CreateCRUDataAction implements Action {
private final RRI rri;
private final byte[] data;

private CreateCRUDataAction(RRI rri, byte[] data) {
this.rri = rri;
this.data = Objects.requireNonNull(data);
}

public static CreateCRUDataAction create(RRI rri, byte[] data) {
return new CreateCRUDataAction(rri, data);
}

public byte[] getData() {
return this.data;
}

public RRI getRRI() {
return this.rri;
}

@Override
public String toString() {
String dataString = this.data == null ? "null" : Bytes.toBase64String(this.data);
return String.format("%s[%s:%s]", getClass().getSimpleName(), this.rri, dataString);
}
}
Loading