Merge branch 'upgrade-schema-2020-03' of https://github.com/AlphaWallet/alpha-wallet-android into upgrade-schema-2020-03

pull/1263/head
James Brown 5 years ago
commit 5c59c5c749
  1. 105
      lib/src/main/java/com/alphawallet/token/entity/AttributeType.java
  2. 12
      lib/src/main/java/com/alphawallet/token/entity/ContractInfo.java
  3. 60
      lib/src/main/java/com/alphawallet/token/entity/EventDefinition.java
  4. 89
      lib/src/main/java/com/alphawallet/token/entity/Module.java
  5. 120
      lib/src/main/java/com/alphawallet/token/tools/TokenDefinition.java

@ -34,45 +34,22 @@ public class AttributeType {
public Map<BigInteger, String> members;
private TokenDefinition definition;
public FunctionDefinition function = null;
public EventDefinition event = null;
public boolean userInput = false;
public AttributeType(Element attr, TokenDefinition def)
{
definition = def;
id = attr.getAttribute("id");
name = id; //set name to id if not specified
as = As.Unsigned; //default value
try {
switch (attr.getAttribute("syntax")) { // We don't validate syntax here; schema does it.
case "1.3.6.1.4.1.1466.115.121.1.6":
syntax = TokenDefinition.Syntax.BitString;
break;
case "1.3.6.1.4.1.1466.115.121.1.7":
syntax = TokenDefinition.Syntax.Boolean;
break;
case "1.3.6.1.4.1.1466.115.121.1.11":
syntax = TokenDefinition.Syntax.CountryString;
break;
case "1.3.6.1.4.1.1466.115.121.1.28":
syntax = TokenDefinition.Syntax.JPEG;
break;
case "1.3.6.1.4.1.1466.115.121.1.36":
syntax = TokenDefinition.Syntax.NumericString;
break;
case "1.3.6.1.4.1.1466.115.121.1.24":
syntax = TokenDefinition.Syntax.GeneralizedTime;
break;
case "1.3.6.1.4.1.1466.115.121.1.26":
syntax = TokenDefinition.Syntax.IA5String;
break;
case "1.3.6.1.4.1.1466.115.121.1.27":
syntax = TokenDefinition.Syntax.Integer;
break;
default: // unknown syntax treat as Directory String
syntax = TokenDefinition.Syntax.DirectoryString;
}
} catch (NullPointerException e) { // missing <syntax>
if(attr.getAttribute("syntax") != null) {
syntax = getSyntax(attr.getAttribute("syntax"));
} else {
syntax = TokenDefinition.Syntax.DirectoryString; // 1.3.6.1.4.1.1466.115.121.1.15
}
for(Node node = attr.getFirstChild();
node!=null; node=node.getNextSibling()){
if (node.getNodeType() == Node.ELEMENT_NODE) {
@ -107,6 +84,30 @@ public class AttributeType {
}
}
private TokenDefinition.Syntax getSyntax(String ISO) {
switch (ISO) {
case "1.3.6.1.4.1.1466.115.121.1.6":
return TokenDefinition.Syntax.BitString;
case "1.3.6.1.4.1.1466.115.121.1.7":
return TokenDefinition.Syntax.Boolean;
case "1.3.6.1.4.1.1466.115.121.1.11":
return TokenDefinition.Syntax.CountryString;
case "1.3.6.1.4.1.1466.115.121.1.28":
return TokenDefinition.Syntax.JPEG;
case "1.3.6.1.4.1.1466.115.121.1.36":
return TokenDefinition.Syntax.NumericString;
case "1.3.6.1.4.1.1466.115.121.1.24":
return TokenDefinition.Syntax.GeneralizedTime;
case "1.3.6.1.4.1.1466.115.121.1.26":
return TokenDefinition.Syntax.IA5String;
case "1.3.6.1.4.1.1466.115.121.1.27":
return TokenDefinition.Syntax.Integer;
case "1.3.6.1.4.1.1466.115.121.1.15":
return TokenDefinition.Syntax.DirectoryString;
}
return null;
}
private void handleOrigins(Element origin)
{
for(Node node = origin.getFirstChild();
@ -119,7 +120,15 @@ public class AttributeType {
switch (node.getLocalName())
{
case "ethereum":
function = definition.parseFunction(resolve, syntax);
if (resolve.hasAttribute("event"))
{
event = definition.parseEvent(resolve, syntax);
event.attributeId = id;
}
else if (resolve.hasAttribute("function"))
{
function = definition.parseFunction(resolve, syntax);
}
//drop through (no break)
case "token-id":
//this value is obtained from the token id
@ -234,6 +243,40 @@ public class AttributeType {
}
}
//Sometimes value needs to be processed from the raw input.
//Currently only time
public BigInteger processValue(BigInteger val)
{
switch (syntax)
{
case GeneralizedTime:
return parseGeneralizedTime(val);
case DirectoryString:
case IA5String:
case Integer:
case Boolean:
case BitString:
case CountryString:
case JPEG:
case NumericString:
break;
}
return val;
}
private BigInteger parseGeneralizedTime(BigInteger value) {
try
{
DateTime dt = DateTimeFactory.getDateTime(toString(value));
return BigInteger.valueOf(dt.toEpoch());
}
catch (ParseException|UnsupportedEncodingException p)
{
p.printStackTrace();
return value;
}
}
private String checkAlphaNum(String data)
{
for (char ch : data.toCharArray())

@ -12,4 +12,16 @@ public class ContractInfo
{
public String contractInterface = null;
public Map<Integer, List<String>> addresses = new HashMap<>();
public Map<String, Module> eventModules = null;
public boolean hasContractTokenScript(int chainId, String address)
{
if (addresses == null)
{
return false;
} else {
List<String> addrs = addresses.get(chainId);
return addrs != null && addrs.contains(address);
}
}
}

@ -0,0 +1,60 @@
package com.alphawallet.token.entity;
import java.math.BigInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by JB on 21/03/2020.
*/
public class EventDefinition
{
public ContractInfo originContract;
public String attributeId; //TransactionResult: method
public String eventName;
public Module eventModule;
public String filter;
public String select;
public BigInteger readBlock;
public boolean hasNewEvent = false;
public String getFilterTopicValue()
{
// (\+\d{4}|\-\d{4})
Matcher m = Pattern.compile("\\$\\{([^}]+)\\}").matcher(filter);
String item = m.find() ? m.group(1) : null;
return item;
}
public String getFilterTopicIndex()
{
String[] item = filter.split("=");
return item[0];
}
public int getTopicIndex(String filterTopic)
{
if (eventModule == null || filterTopic == null) return -1;
return eventModule.getTopicIndex(filterTopic);
}
public int getSelectIndex(boolean indexed)
{
int index = 0;
boolean found = false;
for (String label : eventModule.getArgNames(indexed))
{
if (label.equals(select))
{
found = true;
break;
}
else
{
index++;
}
}
return found ? index : -1;
}
}

@ -0,0 +1,89 @@
package com.alphawallet.token.entity;
import org.w3c.dom.Element;
import java.util.ArrayList;
import java.util.List;
/**
* Created by JB on 20/03/2020.
*/
public class Module
{
public final ContractInfo contractInfo;
public List<SequenceElement> sequence = new ArrayList<>();
public Module(ContractInfo info)
{
contractInfo = info;
}
public void addSequenceElement(Element element, String sequenceName) throws Exception
{
SequenceElement se = new SequenceElement();
String indexed = element.getAttribute("ethereum:indexed");
se.indexed = indexed != null && indexed.equalsIgnoreCase("true");
se.type = element.getAttribute("ethereum:type");
se.name = element.getAttribute("name");
sequence.add(se);
if (se.type == null)
{
throw new Exception("Malformed sequence element in: " + sequenceName + " name: " + se.name);
}
else if (se.name == null)
{
throw new Exception("Malformed sequence element in: " + sequenceName + " type: " + se.type);
}
}
public List<SequenceElement> getSequenceArgs()
{
return sequence;
}
public List<String> getArgNames(boolean indexed)
{
List<String> argNameIndexedList = new ArrayList<>();
for (SequenceElement se : sequence)
{
if (se.indexed == indexed)
{
argNameIndexedList.add(se.name);
}
}
return argNameIndexedList;
}
int getTopicIndex(String filterTopic)
{
int topicIndex = -1;
int currentIndex = 0;
for (SequenceElement se : sequence)
{
if (se.indexed)
{
if (se.name.equals(filterTopic))
{
topicIndex = currentIndex;
break;
}
else
{
currentIndex++;
}
}
}
return topicIndex;
}
public class SequenceElement
{
public String name;
public String type;
public boolean indexed;
}
}

@ -3,6 +3,7 @@ package com.alphawallet.token.tools;
import com.alphawallet.token.entity.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@ -26,6 +27,7 @@ public class TokenDefinition {
public Map<String, Map<String, String>> attributeSets = new HashMap<>(); //TODO: add language, in case user changes language during operation - see Weiwu's comment further down
public Map<String, TSAction> actions = new HashMap<>();
private Map<String, String> names = new HashMap<>(); // store plural etc for token name
private Map<String, Module> moduleLookup = null; //used to protect against name collision
public String nameSpace;
public TokenscriptContext context;
@ -76,10 +78,35 @@ public class TokenDefinition {
return defs;
}
public EventDefinition parseEvent(Element resolve, Syntax syntax)
{
EventDefinition ev = new EventDefinition();
for (int i = 0; i < resolve.getAttributes().getLength(); i++)
{
Node thisAttr = resolve.getAttributes().item(i);
String attrValue = thisAttr.getNodeValue();
switch (thisAttr.getNodeName())
{
case "event":
ev.eventName = attrValue;
ev.eventModule = moduleLookup.get(attrValue);
break;
case "filter":
ev.filter = attrValue;
break;
case "select":
ev.select = attrValue;
break;
}
}
return ev;
}
public FunctionDefinition parseFunction(Element resolve, Syntax syntax)
{
FunctionDefinition function = new FunctionDefinition();
//this value is obtained from a contract call
String contract = resolve.getAttribute("contract");
function.contract = contracts.get(contract);
function.method = resolve.getAttribute("function");
@ -673,7 +700,7 @@ public class TokenDefinition {
}
}
private void parseOrigins(Element origins)
private void parseOrigins(Element origins) throws SAXParseException
{
for (Node n = origins.getFirstChild(); n != null; n = n.getNextSibling())
{
@ -693,7 +720,7 @@ public class TokenDefinition {
}
}
private void handleAddresses(Element contract)
private void handleAddresses(Element contract) throws Exception
{
NodeList nList = contract.getElementsByTagNameNS(nameSpace, "address");
ContractInfo info = new ContractInfo();
@ -701,31 +728,90 @@ public class TokenDefinition {
info.contractInterface = contract.getAttribute("interface");
contracts.put(name, info);
for (int addrIndex = 0; addrIndex < nList.getLength(); addrIndex++)
for (Node n = contract.getFirstChild(); n != null; n = n.getNextSibling())
{
Node node = nList.item(addrIndex);
if (node.getNodeType() == ELEMENT_NODE)
if (n.getNodeType() == ELEMENT_NODE)
{
Element addressElement = (Element) node;
String networkStr = addressElement.getAttribute("network");
int network = 1;
if (networkStr != null) network = Integer.parseInt(networkStr);
String address = addressElement.getTextContent().toLowerCase();
List<String> addresses = info.addresses.get(network);
if (addresses == null)
Element element = (Element) n;
switch (element.getLocalName())
{
addresses = new ArrayList<>();
info.addresses.put(network, addresses);
case "address":
handleAddress(element, info);
break;
case "module":
handleModule(element, info);
break;
}
}
}
}
private void handleModule(Element module, ContractInfo info) throws Exception
{
String moduleName = module.getAttribute("name");
if (moduleName == null) throw new Exception("Module requires name");
if (moduleLookup == null)
{
moduleLookup = new HashMap<>();
}
else if (moduleLookup.containsKey(moduleName))
{
throw new Exception("Duplicate Module name: " + moduleName);
}
if (!addresses.contains(address))
for (Node n = module.getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeType() == ELEMENT_NODE)
{
switch (n.getNodeName())
{
addresses.add(address);
case "sequence":
Module eventModule = handleElementSequence((Element)n, info, moduleName);
if (info.eventModules == null) info.eventModules = new HashMap<>();
info.eventModules.put(moduleName, eventModule);
moduleLookup.put(moduleName, eventModule);
break;
default:
break;
}
}
}
}
private Module handleElementSequence(Element sequence, ContractInfo info, String moduleName) throws Exception
{
Module module = new Module(info);
for (Node n = sequence.getFirstChild(); n != null; n = n.getNextSibling())
{
if (n.getNodeType() == ELEMENT_NODE)
{
Element element = (Element)n;
module.addSequenceElement(element, moduleName);
}
}
return module;
}
private void handleAddress(Element addressElement, ContractInfo info)
{
String networkStr = addressElement.getAttribute("network");
int network = 1;
if (networkStr != null) network = Integer.parseInt(networkStr);
String address = addressElement.getTextContent().toLowerCase();
List<String> addresses = info.addresses.get(network);
if (addresses == null)
{
addresses = new ArrayList<>();
info.addresses.put(network, addresses);
}
if (!addresses.contains(address))
{
addresses.add(address);
}
}
private String getHTMLContent(Node content)
{
StringBuilder sb = new StringBuilder();

Loading…
Cancel
Save