-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
introduce func smart contracts' compilation without leaving your IDE.
add GenericSmartContract where user can specify any codeCell and dataCell. todo: test on other platforms, detect FIFTPATH automatically.
- Loading branch information
Showing
9 changed files
with
1,138 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
134 changes: 134 additions & 0 deletions
134
smartcontract/src/main/java/org/ton/java/smartcontract/FuncCompiler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package org.ton.java.smartcontract; | ||
|
||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.extern.java.Log; | ||
import org.apache.commons.io.FileUtils; | ||
import org.apache.commons.io.IOUtils; | ||
import org.apache.commons.lang3.ArrayUtils; | ||
import org.apache.commons.lang3.StringUtils; | ||
import org.apache.commons.lang3.tuple.Pair; | ||
import org.ton.java.utils.Utils; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.nio.charset.Charset; | ||
import java.util.concurrent.ExecutionException; | ||
import java.util.concurrent.ExecutorService; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.Future; | ||
|
||
import static java.util.Objects.nonNull; | ||
|
||
/** | ||
* Make sure you have fift and func installed. See <a href="https://github.com/ton-blockchain/packages">packages</a> for instructions. | ||
*/ | ||
@Builder | ||
@Getter | ||
@Log | ||
public class FuncCompiler { | ||
|
||
String contractPath; | ||
String funcExecutablePath; | ||
String fiftExecutablePath; | ||
String fiftAsmLibraryPath; | ||
String fiftSmartcontLibraryPath; | ||
|
||
public static class FuncCompilerBuilder { | ||
} | ||
|
||
public static FuncCompilerBuilder builder() { | ||
return new CustomFuncCompilerBuilder(); | ||
} | ||
|
||
private static class CustomFuncCompilerBuilder extends FuncCompilerBuilder { | ||
@Override | ||
public FuncCompiler build() { | ||
|
||
return super.build(); | ||
} | ||
} | ||
|
||
/** | ||
* @return code of BoC in hex | ||
*/ | ||
public String compile() throws IOException, ExecutionException, InterruptedException { | ||
|
||
String outputFiftAsmFile = executeFunc("-W", "dummy.boc", contractPath); | ||
outputFiftAsmFile = StringUtils.replace(outputFiftAsmFile, "2 boc+>B", "0 boc+>B"); | ||
File file = new File(new File(contractPath).getParent() + "/dummy.fif"); | ||
|
||
FileUtils.writeStringToFile(file, outputFiftAsmFile, Charset.defaultCharset()); | ||
|
||
// output binary boc file | ||
executeFift("-s", file.getAbsolutePath()); | ||
byte[] bocContent = FileUtils.readFileToByteArray(new File(file.getParent() + "/dummy.boc")); | ||
return Utils.bytesToHex(bocContent); | ||
} | ||
|
||
public String executeFunc(String... params) throws ExecutionException, InterruptedException { | ||
Pair<Process, Future<String>> result = execute("func", params); | ||
|
||
return result.getRight().get(); | ||
} | ||
|
||
public String executeFift(String... params) { | ||
String[] withInclude = new String[]{"-I", fiftAsmLibraryPath + ":" + fiftSmartcontLibraryPath}; | ||
String[] all = ArrayUtils.addAll(withInclude, params); | ||
Pair<Process, Future<String>> result = execute("fift", all); | ||
if (nonNull(result)) { | ||
try { | ||
return result.getRight().get(); | ||
} catch (Exception e) { | ||
log.info("executeFift error " + e.getMessage()); | ||
return null; | ||
} | ||
} else { | ||
return null; | ||
} | ||
} | ||
|
||
public Pair<Process, Future<String>> execute(String pathToBinary, String... command) { | ||
|
||
String[] withBinaryCommand = new String[]{pathToBinary}; | ||
|
||
withBinaryCommand = ArrayUtils.addAll(withBinaryCommand, command); | ||
|
||
try { | ||
log.info("execute: " + String.join(" ", withBinaryCommand)); | ||
|
||
ExecutorService executorService = Executors.newSingleThreadExecutor(); | ||
|
||
final ProcessBuilder pb = new ProcessBuilder(withBinaryCommand).redirectErrorStream(true); | ||
|
||
pb.directory(new File(new File(contractPath).getParent())); | ||
Process p = pb.start(); | ||
|
||
Future<String> future = executorService.submit(() -> { | ||
|
||
Thread.currentThread().setName(pathToBinary); | ||
|
||
String resultInput = IOUtils.toString(p.getInputStream(), Charset.defaultCharset()); | ||
|
||
p.getInputStream().close(); | ||
p.getErrorStream().close(); | ||
p.getOutputStream().close(); | ||
if (p.exitValue() != 0) { | ||
log.info("exit value " + p.exitValue()); | ||
log.info(resultInput); | ||
throw new Exception("Cannot compile smart-contract."); | ||
|
||
} | ||
return resultInput; | ||
}); | ||
|
||
executorService.shutdown(); | ||
|
||
return Pair.of(p, future); | ||
|
||
} catch (final IOException e) { | ||
log.info(e.getMessage()); | ||
return null; | ||
} | ||
} | ||
} |
90 changes: 90 additions & 0 deletions
90
smartcontract/src/main/java/org/ton/java/smartcontract/GenericSmartContract.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package org.ton.java.smartcontract; | ||
|
||
|
||
import com.iwebpp.crypto.TweetNaclFast; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import org.ton.java.cell.Cell; | ||
import org.ton.java.cell.CellBuilder; | ||
import org.ton.java.smartcontract.wallet.Contract; | ||
import org.ton.java.tlb.types.ExternalMessageInfo; | ||
import org.ton.java.tlb.types.Message; | ||
import org.ton.java.tonlib.Tonlib; | ||
import org.ton.java.tonlib.types.ExtMessageInfo; | ||
import org.ton.java.utils.Utils; | ||
|
||
import static java.util.Objects.isNull; | ||
|
||
@Builder | ||
@Getter | ||
public class GenericSmartContract implements Contract { | ||
|
||
TweetNaclFast.Signature.KeyPair keyPair; | ||
String code; | ||
String data; | ||
private Tonlib tonlib; | ||
private long wc; | ||
|
||
|
||
@Override | ||
public long getWorkchain() { | ||
return wc; | ||
} | ||
|
||
@Override | ||
public String getName() { | ||
return "GenericSmartContract"; | ||
} | ||
|
||
@Override | ||
public Cell createCodeCell() { | ||
return CellBuilder.beginCell() | ||
.fromBoc(code) | ||
.endCell(); | ||
} | ||
|
||
@Override | ||
public Cell createDataCell() { | ||
return CellBuilder.beginCell() | ||
.fromBoc(data) | ||
.endCell(); | ||
} | ||
|
||
|
||
public static class GenericSmartContractBuilder { | ||
} | ||
|
||
public static GenericSmartContractBuilder builder() { | ||
return new CustomGenericSmartContractBuilder(); | ||
} | ||
|
||
private static class CustomGenericSmartContractBuilder extends GenericSmartContractBuilder { | ||
@Override | ||
public GenericSmartContract build() { | ||
if (isNull(super.keyPair)) { | ||
super.keyPair = Utils.generateSignatureKeyPair(); | ||
} | ||
return super.build(); | ||
} | ||
} | ||
|
||
public ExtMessageInfo deploy(Cell deployMessageBody) { | ||
return tonlib.sendRawMessage(prepareDeployMsg(deployMessageBody).toCell().toBase64()); | ||
} | ||
|
||
public Message prepareDeployMsg(Cell deployMessageBody) { | ||
|
||
Cell body = deployMessageBody; | ||
|
||
return Message.builder() | ||
.info(ExternalMessageInfo.builder() | ||
.dstAddr(getAddressIntStd()) | ||
.build()) | ||
.init(getStateInit()) | ||
.body(CellBuilder.beginCell() | ||
.storeBytes(Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), body.hash())) | ||
.storeCell(body) | ||
.endCell()) | ||
.build(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.