com.klaytn.caver.transaction.utils.AccessTuple Maven / Gradle / Ivy
/*
* Copyright 2022 The caver-java Authors
*
* Licensed under the Apache License, Version 2.0 (the “License”);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an “AS IS” BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.klaytn.caver.transaction.utils;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.klaytn.caver.utils.Utils;
import org.web3j.rlp.RlpEncoder;
import org.web3j.rlp.RlpList;
import org.web3j.rlp.RlpString;
import org.web3j.rlp.RlpType;
import org.web3j.utils.Numeric;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* AccessTuple is a class representing an element of EIP-2930 access list.
*/
@JsonDeserialize(using = AccessTuple.AccessTupleDeserializer.class)
public class AccessTuple {
private String address;
private List storageKeys;
/**
* Create an AccessTuple instance.
* @param address An address string.
* @param storageKeys A list of storage keys.
*/
public AccessTuple(String address, List storageKeys) {
this.setAddress(address);
this.setStorageKeys(storageKeys);
}
/**
* Create an AccessTuple instance.
* @param address
* @param storageKeys
*/
public static AccessTuple create(String address, List storageKeys) {
return new AccessTuple(address, storageKeys);
}
/**
* Getter function of address.
* @return String
*/
public String getAddress() {
return address;
}
/**
* Setter function of address.
* @param address
*/
public void setAddress(String address) {
if (!Utils.isAddress(address)) {
throw new IllegalArgumentException("Invalid address. Address: " + address);
}
this.address = Utils.addHexPrefix(address);
}
/**
* Getter function of storageKeys.
* @return List<String>
*/
public List getStorageKeys() {
return storageKeys;
}
/**
* Setter function of storageKeys.
* @param storageKeys A list of storage keys.
*/
public void setStorageKeys(List storageKeys) {
for (int i = 0; i < storageKeys.size(); i++) {
String storageKey = Utils.addHexPrefix(storageKeys.get(i).toLowerCase());
if (!Utils.isHex(storageKey) || storageKey.length() != 66) {
throw new IllegalArgumentException("Invalid storageKey. Storage key should be a 32 bytes of hex string " + storageKey);
}
storageKeys.set(i, storageKey);
}
java.util.Collections.sort(storageKeys);
this.storageKeys = storageKeys;
}
/**
* Decodes given RlpList to AccessTuple.
* @param rlpEncodedAccessTuple RlpList representing rlp encoded access tuple.
* @return
*/
public static AccessTuple decode(RlpList rlpEncodedAccessTuple) {
try {
List accessTupleRlp = rlpEncodedAccessTuple.getValues();
String address = ((RlpString) accessTupleRlp.get(0)).asString();
List storageKeys = new ArrayList<>();
List storageKeysRlpType = ((RlpList) (accessTupleRlp.get(1))).getValues();
for (RlpType storageKeyRlpType : storageKeysRlpType) {
storageKeys.add(((RlpString) storageKeyRlpType).asString()); }
return new AccessTuple(address, storageKeys);
} catch (Exception e) {
throw new RuntimeException("There is an error while decoding process.");
}
}
/**
* Returns the RLP-encoded string of this accessTuple.
*
* @return RlpList
*/
public RlpList toRlpList() {
List storageKeysRLPList = new ArrayList<>();
for (String storageKey : getStorageKeys()) {
storageKeysRLPList.add(RlpString.create(Numeric.hexStringToByteArray(storageKey)));
}
return new RlpList(
RlpString.create(Numeric.hexStringToByteArray(getAddress())),
new RlpList(storageKeysRLPList)
);
}
/**
* Returns an encoded access tuple.
*
* @return byte[]
*/
public byte[] encodeToBytes() {
RlpList rlPList = this.toRlpList();
return RlpEncoder.encode(rlPList);
}
/**
* Indicates whether some other object is "equal to" this one.
*
* @param o The reference object with which to compare.
* @return boolean
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AccessTuple that = (AccessTuple) o;
if (!address.equalsIgnoreCase(that.address)) {
return false;
}
if (storageKeys.size() != that.storageKeys.size()) {
return false;
}
for (int i = 0; i < storageKeys.size(); i++) {
if (!storageKeys.get(i).equalsIgnoreCase(that.storageKeys.get(i))) {
return false;
}
}
return true;
}
public static class AccessTupleDeserializer extends JsonDeserializer {
@Override
public AccessTuple deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JsonNode root = p.getCodec().readTree(p);
JsonNode addressNode = root.get("address");
String address = (addressNode == null ? "" : addressNode.textValue());
List storageKeys = new ArrayList<>();
Iterator storageKeysNodeIterator = root.get("storageKeys").iterator();
while (storageKeysNodeIterator.hasNext()) {
storageKeys.add(storageKeysNodeIterator.next().textValue());
}
return new AccessTuple(address, storageKeys);
}
}
}