Initial Merge
1) wire 2) GUI - Serpent Editor - Network Overview - Connection Console 3) Serpent Compiler
|
@ -0,0 +1,49 @@
|
|||
package org.ethereum.geodb;
|
||||
|
||||
import com.maxmind.geoip.Location;
|
||||
import com.maxmind.geoip.LookupService;
|
||||
import com.maxmind.geoip2.DatabaseReader;
|
||||
import com.maxmind.geoip2.exception.GeoIp2Exception;
|
||||
import com.maxmind.geoip2.model.CityResponse;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 24/04/14 20:11
|
||||
*/
|
||||
public class IpGeoDB {
|
||||
|
||||
static{
|
||||
try {
|
||||
|
||||
URL geiIpDBFile = ClassLoader.getSystemResource("GeoLiteCity.dat");
|
||||
File file = new File(geiIpDBFile.toURI());
|
||||
cl = new LookupService(file);
|
||||
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static LookupService cl;
|
||||
|
||||
|
||||
public static Location getLocationForIp(InetAddress ip){
|
||||
try {
|
||||
return cl.getLocation(ip);
|
||||
} catch (Throwable e) {
|
||||
|
||||
// todo: think about this exception, maybe you can do something more reasonable
|
||||
System.out.println(e.getMessage());
|
||||
// e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package org.ethereum.gui;
|
||||
|
||||
import org.ethereum.net.client.ClientPeer;
|
||||
import org.fife.ui.rsyntaxtextarea.*;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.IOException;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* A simple example showing how to modify the fonts and colors used in an
|
||||
* RSyntaxTextArea. There are two methods to do this - via the Java API, and via
|
||||
* an XML file. The latter method is preferred since it's more modular, and
|
||||
* provides a way for your users to customize RSTA in your application.<p>
|
||||
*
|
||||
* This example uses RSyntaxTextArea 2.0.1.<p>
|
||||
*
|
||||
* Project Home: http://fifesoft.com/rsyntaxtextarea<br>
|
||||
* Downloads: https://sourceforge.net/projects/rsyntaxtextarea
|
||||
*/
|
||||
public class ConnectionConsole extends JFrame implements PeerListener{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private RSyntaxTextArea textArea;
|
||||
|
||||
|
||||
public ConnectionConsole() {
|
||||
|
||||
final ConnectionConsole thisConsole = this;
|
||||
|
||||
java.net.URL url = ClassLoader.getSystemResource("ethereum-icon.png");
|
||||
Toolkit kit = Toolkit.getDefaultToolkit();
|
||||
Image img = kit.createImage(url);
|
||||
this.setIconImage(img);
|
||||
|
||||
JPanel cp = new JPanel(new BorderLayout());
|
||||
|
||||
textArea = new RSyntaxTextArea(16, 47);
|
||||
textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_LISP);
|
||||
textArea.setCodeFoldingEnabled(true);
|
||||
textArea.setAntiAliasingEnabled(true);
|
||||
RTextScrollPane sp = new RTextScrollPane(textArea);
|
||||
cp.add(sp);
|
||||
|
||||
setContentPane(cp);
|
||||
setTitle("Connection Console");
|
||||
// setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
pack();
|
||||
setLocation(775, 390);
|
||||
|
||||
this.addComponentListener(new ComponentAdapter() {
|
||||
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) {
|
||||
|
||||
Thread t = new Thread() {
|
||||
public void run() {
|
||||
// new ClientPeer(thisConsole).connect("54.201.28.117", 30303);
|
||||
new ClientPeer(thisConsole).connect("82.217.72.169", 30303);
|
||||
}
|
||||
};
|
||||
t.start();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void console(final String output) {
|
||||
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
textArea.append(output);
|
||||
textArea.append("\n");
|
||||
textArea.setCaretPosition(textArea.getText().length());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Start all Swing applications on the EDT.
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new ConnectionConsole().setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package org.ethereum.gui;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 30/04/14 11:32
|
||||
*/
|
||||
public interface PeerListener {
|
||||
|
||||
public void console(String output);
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
package org.ethereum.gui;
|
||||
|
||||
import com.maxmind.geoip.Location;
|
||||
import com.maxmind.geoip2.model.CityResponse;
|
||||
import org.ethereum.geodb.IpGeoDB;
|
||||
import org.ethereum.util.Utils;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 25/04/14 07:04
|
||||
*/
|
||||
public class PeersTableModel extends AbstractTableModel {
|
||||
|
||||
List<PeerInfo> peerInfoList = new ArrayList<PeerInfo>();
|
||||
|
||||
public PeersTableModel() {
|
||||
|
||||
generateRandomData();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getColumnName(int column) {
|
||||
|
||||
if (column == 0) return "Location";
|
||||
if (column == 1) return "IP";
|
||||
if (column == 2) return "Live";
|
||||
else return "";
|
||||
}
|
||||
|
||||
public boolean isCellEditable(int row, int column) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Class getColumnClass(int column) {
|
||||
if (column == 0) return ImageIcon.class;
|
||||
if (column == 1) return String.class;
|
||||
if (column == 2) return ImageIcon.class;
|
||||
else return String.class;
|
||||
}
|
||||
|
||||
public Object getValueAt(int row, int column) {
|
||||
|
||||
PeerInfo peerInfo = peerInfoList.get(row);
|
||||
|
||||
if (column == 0){
|
||||
|
||||
String countryCode = peerInfo.getLocation().countryCode;
|
||||
URL flagURL = ClassLoader.getSystemResource("flags/" + countryCode + ".png");
|
||||
ImageIcon flagIcon = new ImageIcon(flagURL);
|
||||
|
||||
|
||||
return flagIcon;
|
||||
}
|
||||
|
||||
if (column == 1) return peerInfo.getIp().getHostAddress();
|
||||
if (column == 2) {
|
||||
|
||||
Random random = new Random();
|
||||
boolean isConnected = random.nextBoolean();
|
||||
|
||||
ImageIcon flagIcon = null;
|
||||
if (peerInfo.connected){
|
||||
|
||||
flagIcon = Utils.getImageIcon("connected.png");
|
||||
} else {
|
||||
|
||||
flagIcon = Utils.getImageIcon("disconnected.png");
|
||||
}
|
||||
|
||||
|
||||
return flagIcon;
|
||||
}
|
||||
|
||||
else return "";
|
||||
}
|
||||
|
||||
public int getRowCount() {
|
||||
return this.peerInfoList.size();
|
||||
}
|
||||
|
||||
public int getColumnCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// todo: delete it when stabilized
|
||||
private void generateRandomData(){
|
||||
|
||||
List<String> ips = new ArrayList<String>();
|
||||
ips.add("206.223.168.190");
|
||||
ips.add("94.210.200.192");
|
||||
ips.add("88.69.198.198");
|
||||
ips.add("62.78.198.208");
|
||||
ips.add("71.202.162.40");
|
||||
ips.add("78.55.236.218");
|
||||
ips.add("94.197.120.80");
|
||||
ips.add("85.65.126.45");
|
||||
|
||||
ips.add("110.77.217.185");
|
||||
ips.add("64.231.9.30");
|
||||
ips.add("162.243.203.121");
|
||||
ips.add("82.217.72.169");
|
||||
|
||||
ips.add("99.231.80.166");
|
||||
ips.add("131.104.252.4");
|
||||
ips.add("54.204.10.41");
|
||||
ips.add("54.201.28.117");
|
||||
ips.add("82.240.16.5");
|
||||
ips.add("74.79.23.119");
|
||||
|
||||
|
||||
for (String peer : ips){
|
||||
|
||||
try {
|
||||
|
||||
InetAddress addr = InetAddress.getByName(peer);
|
||||
Location cr = IpGeoDB.getLocationForIp(addr);
|
||||
|
||||
peerInfoList.add(new PeerInfo(cr, addr));
|
||||
|
||||
} catch (UnknownHostException e) {e.printStackTrace(); }
|
||||
}
|
||||
}
|
||||
|
||||
private class PeerInfo{
|
||||
|
||||
Location location;
|
||||
InetAddress ip;
|
||||
boolean connected;
|
||||
|
||||
private PeerInfo(Location location, InetAddress ip) {
|
||||
this.location = location;
|
||||
this.ip = ip;
|
||||
|
||||
Random random = new Random();
|
||||
connected = random.nextBoolean();
|
||||
}
|
||||
|
||||
private InetAddress getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
|
||||
private Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
private boolean isConnected() {
|
||||
return connected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
package org.ethereum.gui;
|
||||
|
||||
import org.ethereum.serpent.SerpentCompiler;
|
||||
import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory;
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.fife.ui.rsyntaxtextarea.TokenMakerFactory;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 24/04/14 11:32
|
||||
*/
|
||||
|
||||
|
||||
public class SerpentEditor extends JFrame {
|
||||
|
||||
private String codeSample = "\n\n\n" +
|
||||
"" +
|
||||
"if !contract.storage[msg.data[0]]:\n" +
|
||||
" contract.storage[msg.data[0]] = msg.data[1]\n" +
|
||||
" return(1)\n" +
|
||||
"else:\n" +
|
||||
" return(0)\n";
|
||||
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SerpentEditor() {
|
||||
|
||||
final JPanel cp = new JPanel(new BorderLayout());
|
||||
final JFrame mainWindow = this;
|
||||
|
||||
java.net.URL url = ClassLoader.getSystemResource("ethereum-icon.png");
|
||||
Toolkit kit = Toolkit.getDefaultToolkit();
|
||||
Image img = kit.createImage(url);
|
||||
this.setIconImage(img);
|
||||
this.setLocation(30, 80);
|
||||
|
||||
AbstractTokenMakerFactory atmf = (AbstractTokenMakerFactory)TokenMakerFactory.getDefaultInstance();
|
||||
atmf.putMapping("text/serpent", "org.ethereum.gui.SerpentTokenMaker");
|
||||
|
||||
final RSyntaxTextArea codeArea = new RSyntaxTextArea(32, 80);
|
||||
codeArea.setSyntaxEditingStyle("text/serpent");
|
||||
codeArea.setCodeFoldingEnabled(true);
|
||||
codeArea.setAntiAliasingEnabled(true);
|
||||
codeArea.setText(codeSample);
|
||||
|
||||
RTextScrollPane sp = new RTextScrollPane(codeArea);
|
||||
|
||||
sp.setFoldIndicatorEnabled(true);
|
||||
cp.setLayout(new BorderLayout());
|
||||
|
||||
final JSplitPane splitPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
|
||||
splitPanel.setOneTouchExpandable(true);
|
||||
splitPanel.setDividerSize(5);
|
||||
splitPanel.setContinuousLayout(true);
|
||||
|
||||
cp.add(splitPanel, BorderLayout.CENTER);
|
||||
splitPanel.add(sp);
|
||||
|
||||
final JTextArea result = new JTextArea();
|
||||
result.setLineWrap(true);
|
||||
result.setWrapStyleWord(true);
|
||||
result.setVisible(false);
|
||||
|
||||
splitPanel.add(result);
|
||||
|
||||
JPanel controlsPanel = new JPanel();
|
||||
FlowLayout fl = new FlowLayout(FlowLayout.LEADING, 30, 5);
|
||||
fl.setAlignment(FlowLayout.RIGHT);
|
||||
controlsPanel.setLayout(fl);
|
||||
|
||||
JButton buildButton = new JButton("Build");
|
||||
buildButton.addActionListener(new ActionListener() {
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
|
||||
String asmResult = "";
|
||||
try {
|
||||
asmResult = SerpentCompiler.compile(codeArea.getText());
|
||||
} catch (Throwable th) {th.printStackTrace();}
|
||||
|
||||
splitPanel.setDividerLocation(0.7);
|
||||
|
||||
result.setVisible(true);
|
||||
result.setText(asmResult);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
controlsPanel.add(buildButton);
|
||||
|
||||
cp.add(controlsPanel, BorderLayout.SOUTH);
|
||||
|
||||
|
||||
setContentPane(cp);
|
||||
setTitle("Serpent Editor");
|
||||
// setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
pack();
|
||||
// setLocationRelativeTo(null);
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Start all Swing applications on the EDT.
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new SerpentEditor().setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,508 @@
|
|||
package org.ethereum.gui;
|
||||
|
||||
import javax.swing.text.Segment;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.*;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 24/04/14 11:52
|
||||
*/
|
||||
|
||||
public class SerpentTokenMaker extends AbstractTokenMaker {
|
||||
|
||||
// http://fifesoft.com/rsyntaxtextarea/doc/CustomSyntaxHighlighting.html
|
||||
|
||||
protected final String operators = ".@:*<>=?|!";
|
||||
|
||||
private int currentTokenStart;
|
||||
private int currentTokenType;
|
||||
|
||||
private boolean bracketVariable; // Whether a variable is of the format %{...}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public SerpentTokenMaker() {
|
||||
super(); // Initializes tokensToHighlight.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks the token to give it the exact ID it deserves before
|
||||
* being passed up to the super method.
|
||||
*
|
||||
* @param segment <code>Segment</code> to get text from.
|
||||
* @param start Start offset in <code>segment</code> of token.
|
||||
* @param end End offset in <code>segment</code> of token.
|
||||
* @param tokenType The token's type.
|
||||
* @param startOffset The offset in the document at which the token occurs.
|
||||
*/
|
||||
@Override
|
||||
public void addToken(Segment segment, int start, int end, int tokenType, int startOffset) {
|
||||
|
||||
switch (tokenType) {
|
||||
// Since reserved words, functions, and data types are all passed
|
||||
// into here as "identifiers," we have to see what the token
|
||||
// really is...
|
||||
case Token.IDENTIFIER:
|
||||
int value = wordsToHighlight.get(segment, start,end);
|
||||
if (value!=-1)
|
||||
tokenType = value;
|
||||
break;
|
||||
}
|
||||
|
||||
super.addToken(segment, start, end, tokenType, startOffset);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the text to place at the beginning and end of a
|
||||
* line to "comment" it in a this programming language.
|
||||
*
|
||||
* @return The start and end strings to add to a line to "comment"
|
||||
* it out.
|
||||
*/
|
||||
@Override
|
||||
public String[] getLineCommentStartAndEnd() {
|
||||
return new String[] { "#", null };
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether tokens of the specified type should have "mark
|
||||
* occurrences" enabled for the current programming language.
|
||||
*
|
||||
* @param type The token type.
|
||||
* @return Whether tokens of this type should have "mark occurrences"
|
||||
* enabled.
|
||||
*/
|
||||
@Override
|
||||
public boolean getMarkOccurrencesOfTokenType(int type) {
|
||||
return type==Token.IDENTIFIER || type==Token.VARIABLE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the words to highlight for Windows batch files.
|
||||
*
|
||||
* @return A <code>TokenMap</code> containing the words to highlight for
|
||||
* Windows batch files.
|
||||
* @see org.fife.ui.rsyntaxtextarea.AbstractTokenMaker#getWordsToHighlight
|
||||
*/
|
||||
@Override
|
||||
public TokenMap getWordsToHighlight() {
|
||||
|
||||
TokenMap tokenMap = new TokenMap(true); // Ignore case.
|
||||
|
||||
int reservedWord = Token.RESERVED_WORD;
|
||||
tokenMap.put("set", reservedWord);
|
||||
tokenMap.put("if", reservedWord);
|
||||
tokenMap.put("else", reservedWord);
|
||||
tokenMap.put("elif", reservedWord);
|
||||
tokenMap.put("seq", reservedWord);
|
||||
tokenMap.put("while", reservedWord);
|
||||
tokenMap.put("byte", reservedWord);
|
||||
tokenMap.put("access", reservedWord);
|
||||
tokenMap.put("arrset", reservedWord);
|
||||
tokenMap.put("set_and_inc", reservedWord);
|
||||
tokenMap.put("array", reservedWord);
|
||||
tokenMap.put("getch", reservedWord);
|
||||
tokenMap.put("setch", reservedWord);
|
||||
tokenMap.put("string", reservedWord);
|
||||
tokenMap.put("send", reservedWord);
|
||||
tokenMap.put("create", reservedWord);
|
||||
tokenMap.put("sha3", reservedWord);
|
||||
tokenMap.put("sha3bytes", reservedWord);
|
||||
tokenMap.put("sload", reservedWord);
|
||||
tokenMap.put("sstore", reservedWord);
|
||||
tokenMap.put("calldataload", reservedWord);
|
||||
tokenMap.put("id", reservedWord);
|
||||
tokenMap.put("return", reservedWord);
|
||||
tokenMap.put("suicide", reservedWord);
|
||||
|
||||
|
||||
tokenMap.put("stop", reservedWord);
|
||||
|
||||
int function = Token.FUNCTION;
|
||||
tokenMap.put("msg", function);
|
||||
tokenMap.put("contract", function);
|
||||
tokenMap.put("block", function);
|
||||
tokenMap.put("tx", function);
|
||||
|
||||
|
||||
return tokenMap;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a peerInfoList of tokens representing the given text.
|
||||
*
|
||||
* @param text The text to break into tokens.
|
||||
* @param startTokenType The token with which to start tokenizing.
|
||||
* @param startOffset The offset at which the line of tokens begins.
|
||||
* @return A linked peerInfoList of tokens representing <code>text</code>.
|
||||
*/
|
||||
public Token getTokenList(Segment text, int startTokenType, final int startOffset) {
|
||||
|
||||
resetTokenList();
|
||||
|
||||
char[] array = text.array;
|
||||
int offset = text.offset;
|
||||
int count = text.count;
|
||||
int end = offset + count;
|
||||
|
||||
// See, when we find a token, its starting position is always of the form:
|
||||
// 'startOffset + (currentTokenStart-offset)'; but since startOffset and
|
||||
// offset are constant, tokens' starting positions become:
|
||||
// 'newStartOffset+currentTokenStart' for one less subtraction operation.
|
||||
int newStartOffset = startOffset - offset;
|
||||
|
||||
currentTokenStart = offset;
|
||||
currentTokenType = startTokenType;
|
||||
|
||||
//beginning:
|
||||
for (int i=offset; i<end; i++) {
|
||||
|
||||
char c = array[i];
|
||||
|
||||
switch (currentTokenType) {
|
||||
|
||||
case Token.NULL:
|
||||
|
||||
currentTokenStart = i; // Starting a new token here.
|
||||
|
||||
switch (c) {
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
currentTokenType = Token.WHITESPACE;
|
||||
break;
|
||||
|
||||
case '"':
|
||||
currentTokenType = Token.ERROR_STRING_DOUBLE;
|
||||
break;
|
||||
|
||||
case '%':
|
||||
currentTokenType = Token.VARIABLE;
|
||||
break;
|
||||
|
||||
// The "separators".
|
||||
case '(':
|
||||
case ')':
|
||||
addToken(text, currentTokenStart,i, Token.SEPARATOR, newStartOffset+currentTokenStart);
|
||||
currentTokenType = Token.NULL;
|
||||
break;
|
||||
|
||||
// The "separators2".
|
||||
case ',':
|
||||
case ';':
|
||||
addToken(text, currentTokenStart,i, Token.IDENTIFIER, newStartOffset+currentTokenStart);
|
||||
currentTokenType = Token.NULL;
|
||||
break;
|
||||
|
||||
// Newer version of EOL comments, or a label
|
||||
case ':':
|
||||
// If this will be the first token added, it is
|
||||
// a new-style comment or a label
|
||||
if (firstToken==null) {
|
||||
if (i<end-1 && array[i+1]==':') { // new-style comment
|
||||
currentTokenType = Token.COMMENT_EOL;
|
||||
}
|
||||
else { // Label
|
||||
currentTokenType = Token.PREPROCESSOR;
|
||||
}
|
||||
}
|
||||
else { // Just a colon
|
||||
currentTokenType = Token.IDENTIFIER;
|
||||
}
|
||||
break;
|
||||
// Newer version of EOL comments, or a label
|
||||
|
||||
default:
|
||||
|
||||
// Just to speed things up a tad, as this will usually be the case (if spaces above failed).
|
||||
if (RSyntaxUtilities.isLetterOrDigit(c) || c=='\\') {
|
||||
currentTokenType = Token.IDENTIFIER;
|
||||
break;
|
||||
}
|
||||
|
||||
int indexOf = operators.indexOf(c,0);
|
||||
if (indexOf>-1) {
|
||||
addToken(text, currentTokenStart,i, Token.OPERATOR, newStartOffset+currentTokenStart);
|
||||
currentTokenType = Token.NULL;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
currentTokenType = Token.IDENTIFIER;
|
||||
break;
|
||||
}
|
||||
|
||||
} // End of switch (c).
|
||||
|
||||
break;
|
||||
|
||||
case Token.WHITESPACE:
|
||||
|
||||
switch (c) {
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
break; // Still whitespace.
|
||||
|
||||
case '"':
|
||||
addToken(text, currentTokenStart,i-1, Token.WHITESPACE, newStartOffset+currentTokenStart);
|
||||
currentTokenStart = i;
|
||||
currentTokenType = Token.ERROR_STRING_DOUBLE;
|
||||
break;
|
||||
|
||||
case '%':
|
||||
addToken(text, currentTokenStart,i-1, Token.WHITESPACE, newStartOffset+currentTokenStart);
|
||||
currentTokenStart = i;
|
||||
currentTokenType = Token.VARIABLE;
|
||||
break;
|
||||
|
||||
// The "separators".
|
||||
case '(':
|
||||
case ')':
|
||||
addToken(text, currentTokenStart,i-1, Token.WHITESPACE, newStartOffset+currentTokenStart);
|
||||
addToken(text, i,i, Token.SEPARATOR, newStartOffset+i);
|
||||
currentTokenType = Token.NULL;
|
||||
break;
|
||||
|
||||
// The "separators2".
|
||||
case ',':
|
||||
case ';':
|
||||
addToken(text, currentTokenStart,i-1, Token.WHITESPACE, newStartOffset+currentTokenStart);
|
||||
addToken(text, i,i, Token.IDENTIFIER, newStartOffset+i);
|
||||
currentTokenType = Token.NULL;
|
||||
break;
|
||||
|
||||
// Newer version of EOL comments, or a label
|
||||
case ':':
|
||||
addToken(text, currentTokenStart,i-1, Token.WHITESPACE, newStartOffset+currentTokenStart);
|
||||
currentTokenStart = i;
|
||||
// If the previous (whitespace) token was the first token
|
||||
// added, this is a new-style comment or a label
|
||||
if (firstToken.getNextToken()==null) {
|
||||
if (i<end-1 && array[i+1]==':') { // new-style comment
|
||||
currentTokenType = Token.COMMENT_EOL;
|
||||
}
|
||||
else { // Label
|
||||
currentTokenType = Token.PREPROCESSOR;
|
||||
}
|
||||
}
|
||||
else { // Just a colon
|
||||
currentTokenType = Token.IDENTIFIER;
|
||||
}
|
||||
break;
|
||||
|
||||
default: // Add the whitespace token and start anew.
|
||||
|
||||
addToken(text, currentTokenStart,i-1, Token.WHITESPACE, newStartOffset+currentTokenStart);
|
||||
currentTokenStart = i;
|
||||
|
||||
// Just to speed things up a tad, as this will usually be the case (if spaces above failed).
|
||||
if (RSyntaxUtilities.isLetterOrDigit(c) || c=='\\') {
|
||||
currentTokenType = Token.IDENTIFIER;
|
||||
break;
|
||||
}
|
||||
|
||||
int indexOf = operators.indexOf(c,0);
|
||||
if (indexOf>-1) {
|
||||
addToken(text, currentTokenStart,i, Token.OPERATOR, newStartOffset+currentTokenStart);
|
||||
currentTokenType = Token.NULL;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
currentTokenType = Token.IDENTIFIER;
|
||||
}
|
||||
|
||||
} // End of switch (c).
|
||||
|
||||
break;
|
||||
|
||||
default: // Should never happen
|
||||
case Token.IDENTIFIER:
|
||||
|
||||
switch (c) {
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
// Check for REM comments.
|
||||
if (i-currentTokenStart==3 &&
|
||||
(array[i-3]=='r' || array[i-3]=='R') &&
|
||||
(array[i-2]=='e' || array[i-2]=='E') &&
|
||||
(array[i-1]=='m' || array[i-1]=='M')) {
|
||||
currentTokenType = Token.COMMENT_EOL;
|
||||
break;
|
||||
}
|
||||
addToken(text, currentTokenStart,i-1, Token.IDENTIFIER, newStartOffset+currentTokenStart);
|
||||
currentTokenStart = i;
|
||||
currentTokenType = Token.WHITESPACE;
|
||||
break;
|
||||
|
||||
case '"':
|
||||
addToken(text, currentTokenStart,i-1, Token.IDENTIFIER, newStartOffset+currentTokenStart);
|
||||
currentTokenStart = i;
|
||||
currentTokenType = Token.ERROR_STRING_DOUBLE;
|
||||
break;
|
||||
|
||||
case '%':
|
||||
addToken(text, currentTokenStart,i-1, Token.IDENTIFIER, newStartOffset+currentTokenStart);
|
||||
currentTokenStart = i;
|
||||
currentTokenType = Token.VARIABLE;
|
||||
break;
|
||||
|
||||
// Should be part of identifiers, but not at end of "REM".
|
||||
case '\\':
|
||||
// Check for REM comments.
|
||||
if (i-currentTokenStart==3 &&
|
||||
(array[i-3]=='r' || array[i-3]=='R') &&
|
||||
(array[i-2]=='e' || array[i-2]=='E') &&
|
||||
(array[i-1]=='m' || array[i-1]=='M')) {
|
||||
currentTokenType = Token.COMMENT_EOL;
|
||||
}
|
||||
break;
|
||||
|
||||
// case '.':
|
||||
case '_':
|
||||
break; // Characters good for identifiers.
|
||||
|
||||
// The "separators".
|
||||
case '(':
|
||||
case ')':
|
||||
addToken(text, currentTokenStart,i-1, Token.IDENTIFIER, newStartOffset+currentTokenStart);
|
||||
addToken(text, i,i, Token.SEPARATOR, newStartOffset+i);
|
||||
currentTokenType = Token.NULL;
|
||||
break;
|
||||
|
||||
// The "separators2".
|
||||
case ',':
|
||||
case ';':
|
||||
addToken(text, currentTokenStart,i-1, Token.IDENTIFIER, newStartOffset+currentTokenStart);
|
||||
addToken(text, i,i, Token.IDENTIFIER, newStartOffset+i);
|
||||
currentTokenType = Token.NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
// Just to speed things up a tad, as this will usually be the case.
|
||||
if (RSyntaxUtilities.isLetterOrDigit(c) || c=='\\') {
|
||||
break;
|
||||
}
|
||||
|
||||
int indexOf = operators.indexOf(c);
|
||||
if (indexOf>-1) {
|
||||
addToken(text, currentTokenStart,i-1, Token.IDENTIFIER, newStartOffset+currentTokenStart);
|
||||
addToken(text, i,i, Token.OPERATOR, newStartOffset+i);
|
||||
currentTokenType = Token.NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise, fall through and assume we're still okay as an IDENTIFIER...
|
||||
|
||||
} // End of switch (c).
|
||||
|
||||
break;
|
||||
|
||||
case Token.COMMENT_EOL:
|
||||
i = end - 1;
|
||||
addToken(text, currentTokenStart,i, Token.COMMENT_EOL, newStartOffset+currentTokenStart);
|
||||
// We need to set token type to null so at the bottom we don't add one more token.
|
||||
currentTokenType = Token.NULL;
|
||||
break;
|
||||
|
||||
case Token.PREPROCESSOR: // Used for labels
|
||||
i = end - 1;
|
||||
addToken(text, currentTokenStart,i, Token.PREPROCESSOR, newStartOffset+currentTokenStart);
|
||||
// We need to set token type to null so at the bottom we don't add one more token.
|
||||
currentTokenType = Token.NULL;
|
||||
break;
|
||||
|
||||
case Token.ERROR_STRING_DOUBLE:
|
||||
|
||||
if (c=='"') {
|
||||
addToken(text, currentTokenStart,i, Token.LITERAL_STRING_DOUBLE_QUOTE, newStartOffset+currentTokenStart);
|
||||
currentTokenStart = i + 1;
|
||||
currentTokenType = Token.NULL;
|
||||
}
|
||||
// Otherwise, we're still an unclosed string...
|
||||
|
||||
break;
|
||||
|
||||
case Token.VARIABLE:
|
||||
|
||||
if (i==currentTokenStart+1) { // first character after '%'.
|
||||
bracketVariable = false;
|
||||
switch (c) {
|
||||
case '{':
|
||||
bracketVariable = true;
|
||||
break;
|
||||
default:
|
||||
if (RSyntaxUtilities.isLetter(c) || c==' ') { // No tab, just space; spaces are okay in variable names.
|
||||
break;
|
||||
}
|
||||
else if (RSyntaxUtilities.isDigit(c)) { // Single-digit command-line argument ("%1").
|
||||
addToken(text, currentTokenStart,i, Token.VARIABLE, newStartOffset+currentTokenStart);
|
||||
currentTokenType = Token.NULL;
|
||||
break;
|
||||
}
|
||||
else { // Anything else, ???.
|
||||
addToken(text, currentTokenStart,i-1, Token.VARIABLE, newStartOffset+currentTokenStart); // ???
|
||||
i--;
|
||||
currentTokenType = Token.NULL;
|
||||
break;
|
||||
}
|
||||
} // End of switch (c).
|
||||
}
|
||||
else { // Character other than first after the '%'.
|
||||
if (bracketVariable==true) {
|
||||
if (c=='}') {
|
||||
addToken(text, currentTokenStart,i, Token.VARIABLE, newStartOffset+currentTokenStart);
|
||||
currentTokenType = Token.NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (c=='%') {
|
||||
addToken(text, currentTokenStart,i, Token.VARIABLE, newStartOffset+currentTokenStart);
|
||||
currentTokenType = Token.NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
} // End of switch (currentTokenType).
|
||||
|
||||
} // End of for (int i=offset; i<end; i++).
|
||||
|
||||
// Deal with the (possibly there) last token.
|
||||
if (currentTokenType != Token.NULL) {
|
||||
|
||||
// Check for REM comments.
|
||||
if (end-currentTokenStart==3 &&
|
||||
(array[end-3]=='r' || array[end-3]=='R') &&
|
||||
(array[end-2]=='e' || array[end-2]=='E') &&
|
||||
(array[end-1]=='m' || array[end-1]=='M')) {
|
||||
currentTokenType = Token.COMMENT_EOL;
|
||||
}
|
||||
|
||||
addToken(text, currentTokenStart,end-1, currentTokenType, newStartOffset+currentTokenStart);
|
||||
}
|
||||
|
||||
addNullToken();
|
||||
|
||||
// Return the first token in our linked peerInfoList.
|
||||
return firstToken;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
package org.ethereum.gui;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.IOException;
|
||||
import javax.swing.*;
|
||||
|
||||
import org.fife.ui.rtextarea.*;
|
||||
import org.fife.ui.rsyntaxtextarea.*;
|
||||
|
||||
/**
|
||||
* A simple example showing how to modify the fonts and colors used in an
|
||||
* RSyntaxTextArea. There are two methods to do this - via the Java API, and via
|
||||
* an XML file. The latter method is preferred since it's more modular, and
|
||||
* provides a way for your users to customize RSTA in your application.<p>
|
||||
*
|
||||
* This example uses RSyntaxTextArea 2.0.1.<p>
|
||||
*
|
||||
* Project Home: http://fifesoft.com/rsyntaxtextarea<br>
|
||||
* Downloads: https://sourceforge.net/projects/rsyntaxtextarea
|
||||
*/
|
||||
public class SyntaxSchemeDemo extends JFrame implements ActionListener {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private RSyntaxTextArea textArea;
|
||||
|
||||
private static final String text = "public class ExampleSource {\n\n"
|
||||
+ " // Check out the crazy modified styles!\n"
|
||||
+ " public static void main(String[] args) {\n"
|
||||
+ " System.out.println(\"Hello, world!\");\n" + " }\n\n"
|
||||
+ "}\n";
|
||||
|
||||
public SyntaxSchemeDemo() {
|
||||
|
||||
java.net.URL url = ClassLoader.getSystemResource("ethereum-icon.png");
|
||||
Toolkit kit = Toolkit.getDefaultToolkit();
|
||||
Image img = kit.createImage(url);
|
||||
this.setIconImage(img);
|
||||
|
||||
JPanel cp = new JPanel(new BorderLayout());
|
||||
|
||||
textArea = new RSyntaxTextArea(20, 60);
|
||||
textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||
textArea.setCodeFoldingEnabled(true);
|
||||
textArea.setAntiAliasingEnabled(true);
|
||||
RTextScrollPane sp = new RTextScrollPane(textArea);
|
||||
cp.add(sp);
|
||||
|
||||
// JPanel buttons = new JPanel();
|
||||
// buttons.setLayout(new FlowLayout());
|
||||
// buttons.add(new JButton("build"));
|
||||
//
|
||||
// cp.add(buttons, BorderLayout.SOUTH);
|
||||
|
||||
textArea.setText(text);
|
||||
|
||||
JMenuBar mb = new JMenuBar();
|
||||
JMenu menu = new JMenu("File");
|
||||
mb.add(menu);
|
||||
JMenuItem changeStyleProgrammaticallyItem = new JMenuItem(
|
||||
"Change Style Programmatically");
|
||||
changeStyleProgrammaticallyItem
|
||||
.setActionCommand("ChangeProgrammatically");
|
||||
changeStyleProgrammaticallyItem.addActionListener(this);
|
||||
menu.add(changeStyleProgrammaticallyItem);
|
||||
JMenuItem changeStyleViaThemesItem = new JMenuItem(
|
||||
"Change Style via Theme XML");
|
||||
changeStyleViaThemesItem.setActionCommand("ChangeViaThemes");
|
||||
changeStyleViaThemesItem.addActionListener(this);
|
||||
menu.add(changeStyleViaThemesItem);
|
||||
// setJMenuBar(mb);
|
||||
|
||||
setContentPane(cp);
|
||||
setTitle("Connection Console");
|
||||
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
pack();
|
||||
setLocationRelativeTo(null);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for the selection of a menu item and performs an action
|
||||
* accordingly.
|
||||
*/
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String command = e.getActionCommand();
|
||||
if ("ChangeProgrammatically".equals(command)) {
|
||||
changeStyleProgrammatically();
|
||||
} else if ("ChangeViaThemes".equals(command)) {
|
||||
changeStyleViaThemeXml();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the styles used in the editor programmatically.
|
||||
*/
|
||||
private void changeStyleProgrammatically() {
|
||||
|
||||
// Set the font for all token types.
|
||||
setFont(textArea, new Font("Comic Sans MS", Font.PLAIN, 16));
|
||||
|
||||
// Change a few things here and there.
|
||||
SyntaxScheme scheme = textArea.getSyntaxScheme();
|
||||
scheme.getStyle(Token.RESERVED_WORD).background = Color.pink;
|
||||
scheme.getStyle(Token.DATA_TYPE).foreground = Color.blue;
|
||||
scheme.getStyle(Token.LITERAL_STRING_DOUBLE_QUOTE).underline = true;
|
||||
scheme.getStyle(Token.COMMENT_EOL).font = new Font("Georgia",
|
||||
Font.ITALIC, 12);
|
||||
|
||||
textArea.revalidate();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the styles used by the editor via an XML file specification. This
|
||||
* method is preferred because of its ease and modularity.
|
||||
*/
|
||||
private void changeStyleViaThemeXml() {
|
||||
try {
|
||||
Theme theme = Theme.load(getClass().getResourceAsStream(
|
||||
"/eclipse_theme.xml"));
|
||||
theme.apply(textArea);
|
||||
} catch (IOException ioe) { // Never happens
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the font for all token types.
|
||||
*
|
||||
* @param textArea The text area to modify.
|
||||
* @param font The font to use.
|
||||
*/
|
||||
public static void setFont(RSyntaxTextArea textArea, Font font) {
|
||||
if (font != null) {
|
||||
SyntaxScheme ss = textArea.getSyntaxScheme();
|
||||
ss = (SyntaxScheme) ss.clone();
|
||||
for (int i = 0; i < ss.getStyleCount(); i++) {
|
||||
if (ss.getStyle(i) != null) {
|
||||
ss.getStyle(i).font = font;
|
||||
}
|
||||
}
|
||||
textArea.setSyntaxScheme(ss);
|
||||
textArea.setFont(font);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Start all Swing applications on the EDT.
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new SyntaxSchemeDemo().setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
package org.ethereum.gui;
|
||||
|
||||
import samples.PeersTableMain;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 30/04/14 06:29
|
||||
*/
|
||||
public class ToolBar extends JFrame {
|
||||
|
||||
public ToolBar() throws HeadlessException {
|
||||
final JPanel cp = new JPanel(new FlowLayout());
|
||||
cp.setBackground(Color.WHITE);
|
||||
|
||||
java.net.URL url = ClassLoader.getSystemResource("ethereum-icon.png");
|
||||
Toolkit kit = Toolkit.getDefaultToolkit();
|
||||
Image img = kit.createImage(url);
|
||||
this.setIconImage(img);
|
||||
this.setSize(350, 130);
|
||||
this.setLocation(460, 25);
|
||||
this.setAlwaysOnTop(true);
|
||||
this.setResizable(false);
|
||||
this.setBackground(Color.WHITE);
|
||||
|
||||
setTitle("EthereumJ Studio");
|
||||
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
|
||||
this.setContentPane(cp);
|
||||
|
||||
|
||||
java.net.URL imageURL_1 = ClassLoader.getSystemResource("buttons/feedly.png");
|
||||
ImageIcon image_1 = new ImageIcon(imageURL_1);
|
||||
|
||||
java.net.URL imageURL_2 = ClassLoader.getSystemResource("buttons/winamp.png");
|
||||
ImageIcon image_2 = new ImageIcon(imageURL_2);
|
||||
|
||||
java.net.URL imageURL_3 = ClassLoader.getSystemResource("buttons/browser.png");
|
||||
ImageIcon image_3 = new ImageIcon(imageURL_3);
|
||||
|
||||
|
||||
|
||||
JToggleButton editorToggle = new JToggleButton("");
|
||||
editorToggle.setIcon(image_1);
|
||||
editorToggle.setContentAreaFilled(true);
|
||||
editorToggle.setToolTipText("Serpent Editor");
|
||||
editorToggle.setBackground(Color.WHITE);
|
||||
editorToggle.setBorderPainted(false);
|
||||
editorToggle.setFocusPainted(false);
|
||||
editorToggle.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||
editorToggle.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new SerpentEditor().setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
JToggleButton logToggle = new JToggleButton();
|
||||
logToggle.setIcon(image_2);
|
||||
logToggle.setToolTipText("Log Console");
|
||||
logToggle.setContentAreaFilled(true);
|
||||
logToggle.setBackground(Color.WHITE);
|
||||
logToggle.setBorderPainted(false);
|
||||
logToggle.setFocusPainted(false);
|
||||
logToggle.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||
logToggle.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new ConnectionConsole().setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
JToggleButton peersToggle = new JToggleButton();
|
||||
peersToggle.setIcon(image_3);
|
||||
peersToggle.setToolTipText("Peers");
|
||||
peersToggle.setContentAreaFilled(true);
|
||||
peersToggle.setBackground(Color.WHITE);
|
||||
peersToggle.setBorderPainted(false);
|
||||
peersToggle.setFocusPainted(false);
|
||||
peersToggle.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||
peersToggle.addActionListener( new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
PeersTableMain mainFrame = new PeersTableMain();
|
||||
mainFrame.setVisible( true );
|
||||
// mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
cp.add(editorToggle);
|
||||
cp.add(logToggle);
|
||||
cp.add(peersToggle);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void main(String args[]){
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new ToolBar().setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package org.ethereum.manager;
|
||||
|
||||
import com.maxmind.geoip.Location;
|
||||
import com.maxmind.geoip2.model.CityResponse;
|
||||
import com.maxmind.geoip2.record.Country;
|
||||
import org.ethereum.geodb.IpGeoDB;
|
||||
import org.ethereum.net.vo.PeerData;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 21/04/14 20:35
|
||||
*/
|
||||
public class MainData {
|
||||
|
||||
private Set<PeerData> peers = Collections.synchronizedSet(new HashSet<PeerData>());
|
||||
|
||||
private List blocks = Collections.synchronizedList(new ArrayList());
|
||||
private List transactions = Collections.synchronizedList(new ArrayList());
|
||||
|
||||
public static MainData instance = new MainData();
|
||||
|
||||
public void addPeers(List newPeers){
|
||||
this.peers.addAll(newPeers);
|
||||
|
||||
|
||||
for (PeerData peerData : this.peers){
|
||||
|
||||
Location location = IpGeoDB.getLocationForIp(peerData.getInetAddress());
|
||||
if (location != null)
|
||||
System.out.println("Hello: " + " [" + peerData.getInetAddress().toString()
|
||||
+ "] " + location.countryName);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void addBlocks(List blocks){}
|
||||
public void addTransactions(List transactions){}
|
||||
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
package org.ethereum.net;
|
||||
|
||||
/**
|
||||
* www.openchain.info
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 04/04/14 00:51
|
||||
*/
|
||||
public class MessageDeserializer {
|
||||
|
||||
|
||||
/**
|
||||
* Get exactly one message payload
|
||||
*/
|
||||
public static void deserialize(byte [] msgData, int level, int startPos, int endPos){
|
||||
|
||||
if (msgData == null || msgData.length == 0) return ;
|
||||
int pos = startPos;
|
||||
|
||||
while(pos < endPos){
|
||||
|
||||
// It's a list with a payload more than 55 bytes
|
||||
// data[0] - 0xF7 = how many next bytes allocated
|
||||
// for the length of the list
|
||||
if ((msgData[pos] & 0xFF) >= 0xF7){
|
||||
|
||||
byte lenghtOfLenght = (byte) (msgData[pos] - 0xF7);
|
||||
byte pow = (byte) (lenghtOfLenght - 1);
|
||||
|
||||
int length = 0;
|
||||
|
||||
for (int i = 1; i <= lenghtOfLenght; ++i){
|
||||
|
||||
length += msgData[pos + i] << (8 * pow);
|
||||
pow--;
|
||||
}
|
||||
|
||||
// now we can parse an item for data[1]..data[length]
|
||||
System.out.println("-- level: [" + level + "] Found big list length: " + length);
|
||||
|
||||
deserialize(msgData, level + 1, pos + lenghtOfLenght + 1, pos + lenghtOfLenght + length);
|
||||
|
||||
pos += lenghtOfLenght + length + 1 ;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// It's a list with a payload less than 55 bytes
|
||||
if ((msgData[pos] & 0xFF) >= 0xC0 && (msgData[pos] & 0xFF) < 0xF7){
|
||||
|
||||
byte length = (byte) (msgData[pos] - 0xC0);
|
||||
|
||||
System.out.println("-- level: [" + level + "] Found small list length: " + length);
|
||||
|
||||
deserialize(msgData, level + 1, pos + 1, pos + length + 1);
|
||||
|
||||
pos += 1 + length;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// It's an item with a payload more than 55 bytes
|
||||
// data[0] - 0xB7 = how much next bytes allocated for
|
||||
// the length of the string
|
||||
if ((msgData[pos] & 0xFF) >= 0xB7 && (msgData[pos] & 0xFF) < 0xC0) {
|
||||
|
||||
byte lenghtOfLenght = (byte) (msgData[pos] - 0xB7);
|
||||
byte pow = (byte) (lenghtOfLenght - 1);
|
||||
|
||||
int length = 0;
|
||||
|
||||
for (int i = 1; i <= lenghtOfLenght; ++i){
|
||||
|
||||
length += msgData[pos + i] << (8 * pow);
|
||||
pow--;
|
||||
}
|
||||
|
||||
|
||||
// now we can parse an item for data[1]..data[length]
|
||||
System.out.println("-- level: [" + level + "] Found big item length: " + length);
|
||||
pos += lenghtOfLenght + length + 1 ;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// It's an item less than 55 bytes long,
|
||||
// data[0] - 0x80 == lenght of the item
|
||||
if ((msgData[pos] & 0xFF) > 0x80 && (msgData[pos] & 0xFF) < 0xB7) {
|
||||
|
||||
byte length = (byte) (msgData[pos] - 0x80);
|
||||
|
||||
System.out.println("-- level: [" + level + "] Found small item length: " + length);
|
||||
pos += 1 + length;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// null item
|
||||
if ((msgData[pos] & 0xFF) == 0x80){
|
||||
System.out.println("-- level: [" + level + "] Found null item: ");
|
||||
pos += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// single byte item
|
||||
if ((msgData[pos] & 0xFF) < 0x80) {
|
||||
System.out.println("-- level: [" + level + "] Found single item: ");
|
||||
pos += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package org.ethereum.net.client;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||
import org.ethereum.gui.PeerListener;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 10/04/14 12:28
|
||||
*/
|
||||
public class ClientPeer {
|
||||
|
||||
PeerListener peerListener;
|
||||
|
||||
public ClientPeer() {
|
||||
}
|
||||
|
||||
public ClientPeer(PeerListener peerListener) {
|
||||
this.peerListener = peerListener;
|
||||
}
|
||||
|
||||
public void connect(String host, int port){
|
||||
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
|
||||
try {
|
||||
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.group(workerGroup);
|
||||
b.channel(NioSocketChannel.class);
|
||||
|
||||
b.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
|
||||
final EthereumProtocolHandler handler;
|
||||
if (peerListener != null){
|
||||
handler = new EthereumProtocolHandler(peerListener);
|
||||
peerListener.console("connecting to: " + host + ":" + port);
|
||||
}
|
||||
else
|
||||
handler = new EthereumProtocolHandler();
|
||||
|
||||
b.handler(new ChannelInitializer<NioSocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(NioSocketChannel ch) throws Exception {
|
||||
|
||||
ch.pipeline().addLast("readTimeoutHandler", new ReadTimeoutHandler(15));
|
||||
ch.pipeline().addLast(new EthereumFrameDecoder());
|
||||
ch.pipeline().addLast(handler);
|
||||
}
|
||||
});
|
||||
|
||||
// Start the client.
|
||||
ChannelFuture f = b.connect(host, port).sync(); // (5)
|
||||
|
||||
// Wait until the connection is closed.
|
||||
f.channel().closeFuture().sync();
|
||||
|
||||
|
||||
} catch (InterruptedException ie){
|
||||
|
||||
System.out.println("-- ClientPeer: catch (InterruptedException ie) --");
|
||||
ie.printStackTrace();
|
||||
} finally {
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package org.ethereum.net.client;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOutboundBuffer;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 13/04/14 21:51
|
||||
*/
|
||||
public class EthereumFrameDecoder extends ByteToMessageDecoder {
|
||||
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
|
||||
// No header for Eth. message
|
||||
if (in.readableBytes() < 8) return;
|
||||
|
||||
long magicBytes = in.readUnsignedInt();
|
||||
long msgSize = in.readUnsignedInt();
|
||||
|
||||
if (!((magicBytes >> 24 & 0xFF) == 0x22 &&
|
||||
(magicBytes >> 16 & 0xFF) == 0x40 &&
|
||||
(magicBytes >> 8 & 0xFF) == 0x08 &&
|
||||
(magicBytes & 0xFF) == 0x91 )){
|
||||
|
||||
System.out.println("Not ethereum packet");
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
|
||||
// Don't have the full packet yet
|
||||
if (msgSize > in.readableBytes()) {
|
||||
|
||||
in.resetReaderIndex();
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] decoded = new byte[(int)msgSize];
|
||||
in.readBytes(decoded);
|
||||
|
||||
out.add(decoded);
|
||||
|
||||
// Chop the achieved data.
|
||||
in.markReaderIndex();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,413 @@
|
|||
package org.ethereum.net.client;
|
||||
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.FixedRecvByteBufAllocator;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.ethereum.gui.PeerListener;
|
||||
import org.ethereum.manager.MainData;
|
||||
import org.ethereum.net.RLP;
|
||||
import org.ethereum.net.message.*;
|
||||
import org.ethereum.net.rlp.RLPList;
|
||||
import org.ethereum.net.vo.BlockData;
|
||||
import org.ethereum.util.Utils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 10/04/14 08:19
|
||||
*/
|
||||
public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
final Timer timer = new Timer();
|
||||
private final static byte[] MAGIC_PREFIX = {(byte)0x22, (byte)0x40, (byte)0x08, (byte)0x91};
|
||||
|
||||
private final static byte[] HELLO_MESSAGE = StaticMessages.HELLO_MESSAGE.getPayload();
|
||||
private final static byte[] HELLO_MESSAGE_LEN = calcPacketLength(HELLO_MESSAGE);
|
||||
|
||||
private long lastPongTime = 0;
|
||||
private boolean tearDown = false;
|
||||
|
||||
|
||||
// hello data
|
||||
private boolean handShaked = false;
|
||||
private byte protocolVersion;
|
||||
private byte networkId;
|
||||
|
||||
private String clientId;
|
||||
private byte capabilities;
|
||||
private short peerPort;
|
||||
private byte[] peerId;
|
||||
|
||||
PeerListener peerListener;
|
||||
|
||||
public EthereumProtocolHandler() { }
|
||||
|
||||
public EthereumProtocolHandler(PeerListener peerListener) {
|
||||
this.peerListener = peerListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(final ChannelHandlerContext ctx) {
|
||||
|
||||
// TODO: send hello
|
||||
// TODO: send ping schedule another ping
|
||||
|
||||
// TODO: ByteBuf vs Stream vs new byte ???
|
||||
|
||||
|
||||
final ByteBuf buffer = ctx.alloc().buffer(HELLO_MESSAGE.length + 8);
|
||||
|
||||
buffer.writeBytes(MAGIC_PREFIX);
|
||||
buffer.writeBytes(HELLO_MESSAGE_LEN);
|
||||
buffer.writeBytes(HELLO_MESSAGE);
|
||||
ctx.writeAndFlush(buffer);
|
||||
|
||||
|
||||
// sample for pinging in background
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
|
||||
public void run() {
|
||||
|
||||
if (lastPongTime == 0) lastPongTime = System.currentTimeMillis();
|
||||
if (tearDown) this.cancel();
|
||||
|
||||
long currTime = System.currentTimeMillis();
|
||||
if (currTime - lastPongTime > 30000){
|
||||
|
||||
System.out.println("No ping answer for [30 sec]");
|
||||
throw new Error("No ping return for 30 [sec]");
|
||||
|
||||
|
||||
// TODO: shutdown the handler
|
||||
}
|
||||
|
||||
System.out.println("[Send: PING]");
|
||||
if (peerListener != null) peerListener.console("[Send: PING]");
|
||||
|
||||
sendPing(ctx);
|
||||
}
|
||||
}, 2000, 5000);
|
||||
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
|
||||
public void run() {
|
||||
|
||||
System.out.println("[Send: GET_PEERS]");
|
||||
sendGetPeers(ctx);
|
||||
}
|
||||
}, 2000, 60000);
|
||||
|
||||
timer.scheduleAtFixedRate(new TimerTask() {
|
||||
|
||||
public void run() {
|
||||
|
||||
System.out.println("[Send: GET_TRANSACTIONS]");
|
||||
sendGetTransactions(ctx);
|
||||
}
|
||||
}, 2000, 30000);
|
||||
|
||||
timer.schedule(new TimerTask() {
|
||||
|
||||
public void run() {
|
||||
|
||||
System.out.println("[Send: GET_CHAIN]");
|
||||
sendGetChain(ctx);
|
||||
}
|
||||
}, 10000);
|
||||
|
||||
/*
|
||||
timer.schedule(new TimerTask() {
|
||||
|
||||
public void run() {
|
||||
|
||||
System.out.println("[Send: TX]");
|
||||
sendTx(ctx);
|
||||
}
|
||||
}, 10000);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
|
||||
|
||||
byte[] payload = (byte[]) msg;
|
||||
|
||||
System.out.print("msg: ");
|
||||
Utils.printHexStringForByteArray(payload);
|
||||
|
||||
byte command = RLP.getCommandCode(payload);
|
||||
|
||||
// got HELLO
|
||||
if ((int) (command & 0xFF) == 0x00) {
|
||||
|
||||
System.out.println("[Recv: HELLO]" );
|
||||
RLPList rlpList = new RLPList();
|
||||
RLP.parseObjects(payload, rlpList);
|
||||
|
||||
HelloMessage helloMessage = new HelloMessage(rlpList);
|
||||
this.protocolVersion = helloMessage.getProtocolVersion();
|
||||
this.networkId = helloMessage.getNetworkId();
|
||||
this.clientId = helloMessage.getClientId();
|
||||
this.capabilities = helloMessage.getCapabilities();
|
||||
this.peerPort = helloMessage.getPeerPort();
|
||||
this.peerId = helloMessage.getPeerId();
|
||||
|
||||
System.out.println(helloMessage.toString());
|
||||
if (peerListener != null) peerListener.console(helloMessage.toString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
// got DISCONNECT
|
||||
if ((int) (command & 0xFF) == 0x01) {
|
||||
|
||||
System.out.println("[Recv: DISCONNECT]");
|
||||
if (peerListener != null) peerListener.console("[Recv: DISCONNECT]");
|
||||
|
||||
RLPList rlpList = new RLPList();
|
||||
RLP.parseObjects(payload, rlpList);
|
||||
DisconnectMessage disconnectMessage = new DisconnectMessage(rlpList);
|
||||
|
||||
System.out.println(disconnectMessage);
|
||||
if (peerListener != null) peerListener.console(disconnectMessage.toString());
|
||||
|
||||
}
|
||||
|
||||
// got PING send pong
|
||||
if ((int) (command & 0xFF) == 0x02) {
|
||||
|
||||
System.out.println("[Recv: PING]");
|
||||
if (peerListener != null) peerListener.console("[Recv: PING]");
|
||||
|
||||
sendPong(ctx);
|
||||
}
|
||||
|
||||
// got PONG mark it
|
||||
if ((int) (command & 0xFF) == 0x03) {
|
||||
|
||||
System.out.println("[Recv: PONG]" );
|
||||
if (peerListener != null) peerListener.console("[Recv: PONG]");
|
||||
|
||||
this.lastPongTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
// got GETPEERS send peers
|
||||
if ((int) (command & 0xFF) == 0x10) {
|
||||
|
||||
System.out.println("[Recv: GETPEERS]" );
|
||||
if (peerListener != null) peerListener.console("[Recv: GETPEERS]");
|
||||
|
||||
|
||||
String answer = "22 40 08 91 00 00 00 50 F8 4E 11 F8 4B C5 36 81 " +
|
||||
"CC 0A 29 82 76 5F B8 40 D8 D6 0C 25 80 FA 79 5C " +
|
||||
"FC 03 13 EF DE BA 86 9D 21 94 E7 9E 7C B2 B5 22 " +
|
||||
"F7 82 FF A0 39 2C BB AB 8D 1B AC 30 12 08 B1 37 " +
|
||||
"E0 DE 49 98 33 4F 3B CF 73 FA 11 7E F2 13 F8 74 " +
|
||||
"17 08 9F EA F8 4C 21 B0 ";
|
||||
|
||||
byte[] answerBytes = Utils.hexStringToByteArr(answer);
|
||||
|
||||
ByteBuf buffer = ctx.alloc().buffer(answerBytes.length);
|
||||
buffer.writeBytes(answerBytes);
|
||||
ctx.writeAndFlush(buffer);
|
||||
|
||||
// send getpeers
|
||||
answer = "22 40 08 91 00 00 00 02 C1 10 ";
|
||||
|
||||
answerBytes = Utils.hexStringToByteArr(answer);
|
||||
|
||||
buffer = ctx.alloc().buffer(answerBytes.length);
|
||||
buffer.writeBytes(answerBytes);
|
||||
ctx.writeAndFlush(buffer);
|
||||
}
|
||||
|
||||
// got PEERS
|
||||
if ((int) (command & 0xFF) == 0x11) {
|
||||
|
||||
System.out.println("[Recv: PEERS]");
|
||||
if (peerListener != null) peerListener.console("[Recv: PEERS]");
|
||||
|
||||
RLPList rlpList = new RLPList();
|
||||
RLP.parseObjects(payload, rlpList);
|
||||
PeersMessage peersMessage = new PeersMessage(rlpList);
|
||||
|
||||
MainData.instance.addPeers(peersMessage.getPeers());
|
||||
|
||||
System.out.println(peersMessage);
|
||||
if (peerListener != null) peerListener.console(peersMessage.toString());
|
||||
}
|
||||
|
||||
// got TRANSACTIONS
|
||||
if ((int) (command & 0xFF) == 0x12) {
|
||||
|
||||
System.out.println("Recv: TRANSACTIONS]");
|
||||
if (peerListener != null) peerListener.console("Recv: TRANSACTIONS]");
|
||||
|
||||
RLPList rlpList = new RLPList();
|
||||
RLP.parseObjects(payload, rlpList);
|
||||
TransactionsMessage transactionsMessage = new TransactionsMessage(rlpList);
|
||||
MainData.instance.addTransactions(transactionsMessage.getTransactions());
|
||||
|
||||
// todo: if you got transactions send it to your peers
|
||||
System.out.println(transactionsMessage);
|
||||
if (peerListener != null) peerListener.console(transactionsMessage.toString());
|
||||
|
||||
}
|
||||
|
||||
// got BLOCKS
|
||||
if ((int) (command & 0xFF) == 0x13) {
|
||||
System.out.println("[Recv: BLOCKS]");
|
||||
if (peerListener != null) peerListener.console("[Recv: BLOCKS]");
|
||||
|
||||
RLPList rlpList = new RLPList();
|
||||
RLP.parseObjects(payload, rlpList);
|
||||
|
||||
BlocksMessage blocksMessage = new BlocksMessage(rlpList);
|
||||
List<BlockData> list = blocksMessage.getBlockDataList();
|
||||
|
||||
MainData.instance.addBlocks(list);
|
||||
System.out.println(blocksMessage);
|
||||
if (peerListener != null) peerListener.console(blocksMessage.toString());
|
||||
}
|
||||
|
||||
// got GETCHAIN
|
||||
if ((int) (command & 0xFF) == 0x14) {
|
||||
System.out.println("[Recv: GET_CHAIN]");
|
||||
if (peerListener != null) peerListener.console("[Recv: GET_CHAIN]");
|
||||
|
||||
RLPList rlpList = new RLPList();
|
||||
RLP.parseObjects(payload, rlpList);
|
||||
GetChainMessage getChainMessage = new GetChainMessage(rlpList);
|
||||
|
||||
System.out.println(getChainMessage);
|
||||
if (peerListener != null) peerListener.console(getChainMessage.toString());
|
||||
}
|
||||
|
||||
// got NOTINCHAIN
|
||||
if ((int) (command & 0xFF) == 0x15) {
|
||||
System.out.println("[Recv: NOT_IN_CHAIN]");
|
||||
if (peerListener != null) peerListener.console("[Recv: NOT_IN_CHAIN]");
|
||||
|
||||
RLPList rlpList = new RLPList();
|
||||
RLP.parseObjects(payload, rlpList);
|
||||
NotInChainMessage notInChainMessage = new NotInChainMessage(rlpList);
|
||||
|
||||
System.out.println(notInChainMessage);
|
||||
if (peerListener != null) peerListener.console(notInChainMessage.toString());
|
||||
}
|
||||
|
||||
// got GETTRANSACTIONS
|
||||
if ((int) (command & 0xFF) == 0x16) {
|
||||
System.out.println("[Recv: GET_TRANSACTIONS]");
|
||||
if (peerListener != null) peerListener.console("[Recv: GET_TRANSACTIONS]");
|
||||
|
||||
// todo: send the queue of the transactions
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
||||
// limit the size of recieving buffer to 1024
|
||||
ctx.channel().config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(32368));
|
||||
ctx.channel().config().setOption(ChannelOption.SO_RCVBUF, 32368);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
|
||||
this.tearDown = true;
|
||||
System.out.println("Lost connection to the server");
|
||||
cause.printStackTrace();
|
||||
ctx.close().sync();
|
||||
timer.cancel();
|
||||
}
|
||||
|
||||
private void sendMsg(Message msg, ChannelHandlerContext ctx){
|
||||
|
||||
byte[] data = msg.getPayload();
|
||||
|
||||
final ByteBuf buffer = ctx.alloc().buffer(data.length + 8);
|
||||
byte[] packetLen = calcPacketLength(data);
|
||||
|
||||
buffer.writeBytes(MAGIC_PREFIX);
|
||||
buffer.writeBytes(packetLen);
|
||||
ctx.writeAndFlush(buffer);
|
||||
}
|
||||
|
||||
|
||||
private void sendPing(ChannelHandlerContext ctx){
|
||||
|
||||
ByteBuf buffer = ctx.alloc().buffer(StaticMessages.PING.length);
|
||||
buffer.writeBytes(StaticMessages.PING);
|
||||
ctx.writeAndFlush(buffer);
|
||||
}
|
||||
|
||||
|
||||
private void sendPong(ChannelHandlerContext ctx){
|
||||
|
||||
System.out.println("[Send: PONG]");
|
||||
ByteBuf buffer = ctx.alloc().buffer(StaticMessages.PONG.length);
|
||||
buffer.writeBytes(StaticMessages.PONG);
|
||||
ctx.writeAndFlush(buffer);
|
||||
}
|
||||
|
||||
private void sendGetPeers(ChannelHandlerContext ctx){
|
||||
|
||||
ByteBuf buffer = ctx.alloc().buffer(StaticMessages.GET_PEERS.length);
|
||||
buffer.writeBytes(StaticMessages.GET_PEERS);
|
||||
ctx.writeAndFlush(buffer);
|
||||
}
|
||||
|
||||
private void sendGetTransactions(ChannelHandlerContext ctx){
|
||||
|
||||
ByteBuf buffer = ctx.alloc().buffer(StaticMessages.GET_TRANSACTIONS.length);
|
||||
buffer.writeBytes(StaticMessages.GET_TRANSACTIONS);
|
||||
ctx.writeAndFlush(buffer);
|
||||
}
|
||||
|
||||
private void sendGetChain(ChannelHandlerContext ctx){
|
||||
|
||||
ByteBuf buffer = ctx.alloc().buffer(StaticMessages.GET_CHAIN.length);
|
||||
buffer.writeBytes(StaticMessages.GET_CHAIN);
|
||||
ctx.writeAndFlush(buffer);
|
||||
}
|
||||
|
||||
private void sendTx(ChannelHandlerContext ctx){
|
||||
|
||||
byte[] TX_MSG =
|
||||
Hex.decode("2240089100000070F86E12F86B80881BC16D674EC8000094CD2A3D9F938E13CD947EC05ABC7FE734DF8DD8268609184E72A00064801BA0C52C114D4F5A3BA904A9B3036E5E118FE0DBB987FE3955DA20F2CD8F6C21AB9CA06BA4C2874299A55AD947DBC98A25EE895AABF6B625C26C435E84BFD70EDF2F69");
|
||||
|
||||
ByteBuf buffer = ctx.alloc().buffer(TX_MSG.length);
|
||||
buffer.writeBytes(TX_MSG);
|
||||
ctx.writeAndFlush(buffer);
|
||||
}
|
||||
|
||||
|
||||
private static byte[] calcPacketLength(byte[] msg){
|
||||
|
||||
int msgLen = msg.length;
|
||||
|
||||
byte[] len = {
|
||||
(byte)((msgLen >> 24) & 0xFF),
|
||||
(byte)((msgLen >> 16) & 0xFF),
|
||||
(byte)((msgLen >> 8) & 0xFF),
|
||||
(byte)((msgLen ) & 0xFF)};
|
||||
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package org.ethereum.net.message;
|
||||
|
||||
import org.ethereum.net.RLP;
|
||||
import org.ethereum.net.rlp.RLPItem;
|
||||
import org.ethereum.net.rlp.RLPList;
|
||||
import org.ethereum.net.vo.BlockData;
|
||||
import org.ethereum.net.vo.TransactionData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 06/04/14 14:56
|
||||
*/
|
||||
public class BlocksMessage extends Message {
|
||||
|
||||
private final byte commandCode = 0x13;
|
||||
|
||||
private List<BlockData> blockDataList = new ArrayList<BlockData>();
|
||||
|
||||
|
||||
public BlocksMessage(RLPList rawData) {
|
||||
super(rawData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void parseRLP() {
|
||||
|
||||
RLPList paramsList = (RLPList) rawData.getElement(0);
|
||||
|
||||
if (((RLPItem)(paramsList).getElement(0)).getData()[0] != commandCode){
|
||||
|
||||
throw new Error("BlocksMessage: parsing for mal data");
|
||||
}
|
||||
|
||||
for (int i = 1; i < paramsList.size(); ++i){
|
||||
|
||||
RLPList rlpData = ((RLPList)paramsList.getElement(i));
|
||||
BlockData blockData = new BlockData(rlpData);
|
||||
this.blockDataList.add(blockData);
|
||||
}
|
||||
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte[] getPayload() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public List<BlockData> getBlockDataList() {
|
||||
if (!parsed) parseRLP();
|
||||
return blockDataList;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (BlockData blockData : this.getBlockDataList()){
|
||||
sb.append(" ").append( blockData.toString() ).append("\n");
|
||||
|
||||
List<TransactionData> transactions = blockData.getTransactionsList();
|
||||
for (TransactionData transactionData : transactions){
|
||||
|
||||
sb.append("[").append(transactionData).append("]\n");
|
||||
}
|
||||
}
|
||||
|
||||
return "Blocks Message [\n" +
|
||||
sb.toString()
|
||||
+ " ]";
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package org.ethereum.net.message;
|
||||
|
||||
import org.ethereum.net.rlp.RLPItem;
|
||||
import org.ethereum.net.rlp.RLPList;
|
||||
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 06/04/14 14:56
|
||||
*/
|
||||
public class DisconnectMessage extends Message {
|
||||
|
||||
private final byte commandCode = 0x1;
|
||||
private byte reason;
|
||||
|
||||
public static byte REASON_DISCONNECT_REQUESTED = 0x00;
|
||||
public static byte REASON_TCP_ERROR = 0x01;
|
||||
public static byte REASON_BAD_PROTOCOL = 0x02;
|
||||
public static byte REASON_USELESS_PEER = 0x03;
|
||||
public static byte REASON_TOO_MANY_PEERS = 0x04;
|
||||
public static byte REASON_ALREADY_CONNECTED = 0x05;
|
||||
public static byte REASON_WRONG_GENESIS = 0x06;
|
||||
public static byte REASON_INCOMPATIBLE_PROTOCOL = 0x07;
|
||||
public static byte REASON_PEER_QUITING = 0x08;
|
||||
|
||||
|
||||
public DisconnectMessage(RLPList rawData) {
|
||||
super(rawData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseRLP() {
|
||||
|
||||
RLPList paramsList = (RLPList) rawData.getElement(0);
|
||||
|
||||
if (((RLPItem)(paramsList).getElement(0)).getData()[0] != commandCode){
|
||||
|
||||
throw new Error("Disconnect: parsing for mal data");
|
||||
}
|
||||
|
||||
byte[] reasonB = ((RLPItem)paramsList.getElement(1)).getData();
|
||||
if (reasonB == null){
|
||||
|
||||
this.reason = 0;
|
||||
} else {
|
||||
|
||||
this.reason = reasonB[0];
|
||||
}
|
||||
|
||||
this.parsed = true;
|
||||
// todo: what to do when mal data ?
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte[] getPayload() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte getReason() {
|
||||
if (!parsed) parseRLP();
|
||||
return reason;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
|
||||
if (!parsed) parseRLP();
|
||||
return "Disconnect Message [ reason=" + reason + " ]";
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package org.ethereum.net.message;
|
||||
|
||||
import org.ethereum.net.RLP;
|
||||
import org.ethereum.net.rlp.RLPItem;
|
||||
import org.ethereum.net.rlp.RLPList;
|
||||
import org.ethereum.util.Utils;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 06/04/14 14:56
|
||||
*/
|
||||
public class GetChainMessage extends Message {
|
||||
|
||||
private final byte commandCode = 0x14;
|
||||
List<byte[]> blockHashList = new ArrayList<byte[]>();
|
||||
BigInteger blockNum;
|
||||
|
||||
|
||||
public GetChainMessage(RLPList rawData) {
|
||||
super(rawData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseRLP() {
|
||||
|
||||
RLPList paramsList = (RLPList) rawData.getElement(0);
|
||||
|
||||
if (((RLPItem)(paramsList).getElement(0)).getData()[0] != commandCode){
|
||||
|
||||
throw new Error("GetChain: parsing for mal data");
|
||||
}
|
||||
|
||||
|
||||
int size = paramsList.size();
|
||||
for (int i = 1; i < size - 1; ++i){
|
||||
|
||||
blockHashList.add(((RLPItem) paramsList.getElement(i)).getData());
|
||||
}
|
||||
|
||||
// the last element is the num of requested blocks
|
||||
byte[] blockNumB = ((RLPItem)paramsList.getElement(size - 1)).getData();
|
||||
this.blockNum = new BigInteger(blockNumB);
|
||||
|
||||
this.parsed = true;
|
||||
// todo: what to do when mal data ?
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getPayload() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<byte[]> getBlockHashList() {
|
||||
if (!parsed) parseRLP();
|
||||
return blockHashList;
|
||||
}
|
||||
|
||||
public BigInteger getBlockNum() {
|
||||
if (!parsed) parseRLP();
|
||||
return blockNum;
|
||||
}
|
||||
|
||||
|
||||
public String toString(){
|
||||
|
||||
if (!parsed) parseRLP();
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (byte[] blockHash : blockHashList){
|
||||
|
||||
sb.append("").append(Utils.toHexString(blockHash)).append(", ");
|
||||
}
|
||||
|
||||
sb.append(" blockNum=").append(blockNum);
|
||||
|
||||
return "GetChain Message [" + sb.toString() + " ]";
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
package org.ethereum.net.message;
|
||||
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.ethereum.net.RLP;
|
||||
import org.ethereum.net.rlp.RLPItem;
|
||||
import org.ethereum.net.rlp.RLPList;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 06/04/14 14:56
|
||||
*/
|
||||
public class HelloMessage extends Message {
|
||||
|
||||
private final byte commandCode = 0x00;
|
||||
|
||||
private byte protocolVersion;
|
||||
private byte networkId;
|
||||
private String clientId;
|
||||
private byte capabilities;
|
||||
private short peerPort;
|
||||
private byte[] peerId;
|
||||
|
||||
|
||||
public HelloMessage(RLPList rawData) {
|
||||
|
||||
super(rawData);
|
||||
}
|
||||
|
||||
|
||||
public HelloMessage(byte protocolVersion, byte networkId, String clientId, byte capabilities, short peerPort, byte[] peerId) {
|
||||
this.protocolVersion = protocolVersion;
|
||||
this.networkId = networkId;
|
||||
this.clientId = clientId;
|
||||
this.capabilities = capabilities;
|
||||
this.peerPort = peerPort;
|
||||
this.peerId = peerId;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void parseRLP() {
|
||||
|
||||
RLPList paramsList = (RLPList) rawData.getElement(0);
|
||||
|
||||
// the message does no distinguish between the 0 and null so here I check command code for null
|
||||
// todo: find out if it can be 00
|
||||
if (((RLPItem)(paramsList).getElement(0)).getData() != null){
|
||||
|
||||
throw new Error("HelloMessage: parsing for mal data");
|
||||
}
|
||||
|
||||
|
||||
this.protocolVersion = ((RLPItem) paramsList.getElement(1)).getData()[0];
|
||||
|
||||
byte[] networkIdBytes = ((RLPItem) paramsList.getElement(2)).getData();
|
||||
this.networkId = networkIdBytes == null ? 0 : networkIdBytes[0] ;
|
||||
|
||||
this.clientId = new String(((RLPItem) paramsList.getElement(3)).getData());
|
||||
this.capabilities = ((RLPItem) paramsList.getElement(4)).getData()[0];
|
||||
|
||||
ByteBuffer bb = ByteBuffer.wrap(((RLPItem) paramsList.getElement(5)).getData());
|
||||
this.peerPort = bb.getShort();
|
||||
|
||||
this.peerId = ((RLPItem) paramsList.getElement(6)).getData();
|
||||
|
||||
this.parsed = true;
|
||||
// todo: what to do when mal data ?
|
||||
}
|
||||
|
||||
|
||||
public byte[] getPayload(){
|
||||
|
||||
byte[] command = RLP.encodeByte(this.commandCode);
|
||||
byte[] protocolVersion = RLP.encodeByte(this.protocolVersion);
|
||||
byte[] networkId = RLP.encodeByte(this.networkId);
|
||||
byte[] clientId = RLP.encodeString(this.clientId);
|
||||
byte[] capabilities = RLP.encodeByte(this.capabilities);
|
||||
byte[] peerPort = RLP.encodeShort(this.peerPort);
|
||||
byte[] peerId = RLP.encodeElement(this.peerId);
|
||||
|
||||
byte[] data = RLP.encodeList(command, protocolVersion, networkId,
|
||||
clientId, capabilities, peerPort, peerId);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
public byte getCommandCode() {
|
||||
|
||||
if (!parsed) parseRLP();
|
||||
return commandCode;
|
||||
}
|
||||
|
||||
public byte getProtocolVersion() {
|
||||
|
||||
if (!parsed) parseRLP();
|
||||
return protocolVersion;
|
||||
}
|
||||
|
||||
public byte getNetworkId() {
|
||||
|
||||
if (!parsed) parseRLP();
|
||||
return networkId;
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
|
||||
if (!parsed) parseRLP();
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public byte getCapabilities() {
|
||||
|
||||
if (!parsed) parseRLP();
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
public short getPeerPort() {
|
||||
|
||||
if (!parsed) parseRLP();
|
||||
return peerPort;
|
||||
}
|
||||
|
||||
public byte[] getPeerId() {
|
||||
|
||||
if (!parsed) parseRLP();
|
||||
return peerId;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
|
||||
return "Hello Message [ command=" + this.commandCode + " " +
|
||||
" protocolVersion=" + this.protocolVersion + " " +
|
||||
" networkId=" + this.networkId + " " +
|
||||
" clientId= " + this.clientId + " " +
|
||||
" capabilities= " + this.capabilities + " " +
|
||||
" peerPort= " + this.peerPort + " " +
|
||||
" peerId= " + Hex.toHexString(this.peerId) + " " +
|
||||
"]";
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package org.ethereum.net.message;
|
||||
|
||||
import org.ethereum.net.rlp.RLPList;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 06/04/14 14:58
|
||||
*/
|
||||
public abstract class Message {
|
||||
|
||||
RLPList rawData;
|
||||
boolean parsed = false;
|
||||
|
||||
|
||||
public Message(){}
|
||||
|
||||
public Message(RLPList rawData) {
|
||||
this.rawData = rawData;
|
||||
parsed = false;
|
||||
}
|
||||
|
||||
public abstract void parseRLP();
|
||||
|
||||
public abstract byte[] getPayload();
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package org.ethereum.net.message;
|
||||
|
||||
import org.ethereum.net.message.Message;
|
||||
import org.ethereum.net.rlp.RLPItem;
|
||||
import org.ethereum.net.rlp.RLPList;
|
||||
import org.ethereum.util.Utils;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 06/04/14 14:56
|
||||
*/
|
||||
public class NotInChainMessage extends Message {
|
||||
|
||||
private final byte commandCode = 0x15;
|
||||
private byte[] hash;
|
||||
|
||||
|
||||
public NotInChainMessage(RLPList rawData) {
|
||||
super(rawData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseRLP() {
|
||||
RLPList paramsList = (RLPList) rawData.getElement(0);
|
||||
|
||||
if ((((RLPItem)(paramsList).getElement(0)).getData()[0] & 0xFF) != commandCode){
|
||||
|
||||
throw new Error("NotInChain Message: parsing for mal data");
|
||||
}
|
||||
|
||||
hash = ((RLPItem)paramsList.getElement(1)).getData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getPayload() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
|
||||
if (!parsed) parseRLP();
|
||||
|
||||
return "NotInChain Message [" + Utils.toHexString(hash) + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package org.ethereum.net.message;
|
||||
|
||||
import org.ethereum.net.RLP;
|
||||
import org.ethereum.net.message.Message;
|
||||
import org.ethereum.net.rlp.RLPItem;
|
||||
import org.ethereum.net.rlp.RLPList;
|
||||
import org.ethereum.net.vo.PeerData;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 06/04/14 14:56
|
||||
*/
|
||||
public class PeersMessage extends Message {
|
||||
|
||||
private final byte commandCode = 0x11;
|
||||
|
||||
RLPList rawData;
|
||||
boolean parsed = false;
|
||||
|
||||
|
||||
List<PeerData> peers = new ArrayList<PeerData>();
|
||||
|
||||
public PeersMessage(){}
|
||||
|
||||
public PeersMessage(RLPList rawData) {
|
||||
this.rawData = rawData;
|
||||
parsed = false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void parseRLP() {
|
||||
|
||||
RLPList paramsList = (RLPList) rawData.getElement(0);
|
||||
|
||||
if ((((RLPItem)(paramsList).getElement(0)).getData()[0] & 0xFF) != commandCode){
|
||||
|
||||
throw new Error("PeersMessage: parsing for mal data");
|
||||
}
|
||||
|
||||
|
||||
for (int i = 1; i < paramsList.size(); ++i){
|
||||
|
||||
RLPList peerParams = (RLPList)paramsList.getElement(i);
|
||||
|
||||
RLPItem ip_a = (RLPItem)((RLPList) peerParams.getElement(0)).getElement(0);
|
||||
RLPItem ip_b = (RLPItem)((RLPList) peerParams.getElement(0)).getElement(1);
|
||||
RLPItem ip_c = (RLPItem)((RLPList) peerParams.getElement(0)).getElement(2);
|
||||
RLPItem ip_d = (RLPItem)((RLPList) peerParams.getElement(0)).getElement(3);
|
||||
byte ipA = ip_a.getData() == null ? 0 : ip_a.getData()[0];
|
||||
byte ipB = ip_b.getData() == null ? 0 : ip_b.getData()[0];
|
||||
byte ipC = ip_c.getData() == null ? 0 : ip_c.getData()[0];
|
||||
byte ipD = ip_d.getData() == null ? 0 : ip_d.getData()[0];
|
||||
|
||||
byte[] ip = new byte[]{ipA, ipB, ipC, ipD};
|
||||
|
||||
byte[] shortData = ((RLPItem) peerParams.getElement(1)).getData();
|
||||
|
||||
short peerPort = 0;
|
||||
if (shortData.length == 1)
|
||||
|
||||
peerPort = shortData[0];
|
||||
else{
|
||||
|
||||
ByteBuffer bb = ByteBuffer.wrap(shortData, 0, shortData.length);
|
||||
peerPort = bb.getShort();
|
||||
}
|
||||
|
||||
byte[] peerId = ((RLPItem) peerParams.getElement(2)).getData();
|
||||
|
||||
PeerData peer = new PeerData(ip, peerPort, peerId);
|
||||
peers.add(peer);
|
||||
}
|
||||
|
||||
this.parsed = true;
|
||||
// todo: what to do when mal data ?
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getPayload() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public List<PeerData> getPeers() {
|
||||
|
||||
if (!parsed){
|
||||
parseRLP();
|
||||
}
|
||||
return peers;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
|
||||
if (!parsed){
|
||||
parseRLP();
|
||||
}
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
for (PeerData peerData : peers){
|
||||
|
||||
sb.append("[").append(peerData).append("] \n ");
|
||||
}
|
||||
|
||||
return "Peers Message [\n " + sb.toString() + "]";
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package org.ethereum.net.message;
|
||||
|
||||
import org.ethereum.util.Utils;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 13/04/14 20:19
|
||||
*/
|
||||
public class StaticMessages {
|
||||
|
||||
public static final byte[] PING = {(byte)0x22, (byte)0x40, (byte)0x08, (byte)0x91,
|
||||
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02,
|
||||
(byte)0xC1, (byte)0x02 };
|
||||
|
||||
public static final byte[] PONG = {(byte)0x22, (byte)0x40, (byte)0x08, (byte)0x91,
|
||||
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02,
|
||||
(byte)0xC1, (byte)0x03 };
|
||||
|
||||
public static final byte[] GET_PEERS = {(byte)0x22, (byte)0x40, (byte)0x08, (byte)0x91,
|
||||
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02,
|
||||
(byte)0xC1, (byte)0x10 };
|
||||
|
||||
public static final byte[] GET_TRANSACTIONS = {(byte)0x22, (byte)0x40, (byte)0x08, (byte)0x91,
|
||||
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02,
|
||||
(byte)0xC1, (byte)0x16 };
|
||||
|
||||
|
||||
public static final byte[] DISCONNECT_00 = {(byte)0x22, (byte)0x40, (byte)0x08, (byte)0x91,
|
||||
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x03,
|
||||
(byte)0xC2, (byte)0x01, (byte)0x00};
|
||||
|
||||
public static final byte[] DISCONNECT_01 = {(byte) 0x22, (byte) 0x40, (byte) 0x08, (byte) 0x91,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03,
|
||||
(byte) 0xC2, (byte) 0x01, (byte) 0x01};
|
||||
|
||||
public static final byte[] DISCONNECT_02 = {(byte) 0x22, (byte) 0x40, (byte) 0x08, (byte) 0x91,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03,
|
||||
(byte) 0xC2, (byte) 0x01, (byte) 0x02};
|
||||
|
||||
public static final byte[] DISCONNECT_03 = {(byte) 0x22, (byte) 0x40, (byte) 0x08, (byte) 0x91,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03,
|
||||
(byte) 0xC2, (byte) 0x01, (byte) 0x03};
|
||||
|
||||
public static final byte[] DISCONNECT_08 = {(byte) 0x22, (byte) 0x40, (byte) 0x08, (byte) 0x91,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03,
|
||||
(byte) 0xC2, (byte) 0x01, (byte) 0x08};
|
||||
|
||||
|
||||
public static final byte[] GET_CHAIN = {
|
||||
|
||||
(byte) 0x22, (byte) 0x40, (byte) 0x08, (byte) 0x91, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x27,
|
||||
(byte) 0xF8, (byte) 0x25, (byte) 0x14, (byte) 0xA0, (byte) 0xAB, (byte) 0x6B, (byte) 0x9A, (byte) 0x56, (byte) 0x13,
|
||||
(byte) 0x97, (byte) 0x0F, (byte) 0xAA, (byte) 0x77, (byte) 0x1B, (byte) 0x12, (byte) 0xD4, (byte) 0x49,
|
||||
(byte) 0xB2, (byte) 0xE9, (byte) 0xBB, (byte) 0x92, (byte) 0x5A, (byte) 0xB7, (byte) 0xA3, (byte) 0x69,
|
||||
(byte) 0xF0, (byte) 0xA4, (byte) 0xB8, (byte) 0x6B, (byte) 0x28, (byte) 0x6E, (byte) 0x9D, (byte) 0x54,
|
||||
(byte) 0x00, (byte) 0x99, (byte) 0xCF, (byte) 0x82, (byte) 0x01, (byte) 0x00,
|
||||
};
|
||||
|
||||
static {
|
||||
String peerId = "CE 73 F1 F1 F1 F1 6C 1B 3F DA 7B 18 EF 7B A3 CE " +
|
||||
"17 B6 F1 F1 F1 F1 41 D3 C6 C6 54 B7 AE 88 B2 39 " +
|
||||
"40 7F F1 F1 F1 F1 19 02 5D 78 57 27 ED 01 7B 6A " +
|
||||
"DD 21 F1 F1 F1 F1 00 00 01 E3 21 DB C3 18 24 BA ";
|
||||
|
||||
byte[] peerIdBytes = Utils.hexStringToByteArr(peerId);
|
||||
|
||||
|
||||
HELLO_MESSAGE = new HelloMessage((byte)0x0C, (byte)0x00, "EthereumJ [v0.0.1] pure java [by Roman Mandeleil]",
|
||||
(byte)0b00000111, (short)30303, peerIdBytes);
|
||||
|
||||
/*
|
||||
HELLO_MESSAGE = new HelloMessage((byte)0x0B, (byte)0x00, "EthereumJ [v0.0.1] pure java [by Roman Mandeleil]",
|
||||
(byte)0b00000111, (short)30303, peerIdBytes);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static final HelloMessage HELLO_MESSAGE;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package org.ethereum.net.message;
|
||||
|
||||
import org.ethereum.net.rlp.RLPItem;
|
||||
import org.ethereum.net.rlp.RLPList;
|
||||
import org.ethereum.net.vo.TransactionData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 06/04/14 14:56
|
||||
*/
|
||||
public class TransactionsMessage extends Message {
|
||||
|
||||
private final byte commandCode = 0x12;
|
||||
private List<TransactionData> transactions = new ArrayList<TransactionData>();
|
||||
|
||||
public TransactionsMessage() {
|
||||
}
|
||||
|
||||
public TransactionsMessage(RLPList rawData) {
|
||||
super(rawData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseRLP() {
|
||||
|
||||
RLPList paramsList = (RLPList) rawData.getElement(0);
|
||||
|
||||
if ((((RLPItem)(paramsList).getElement(0)).getData()[0] & 0xFF) != commandCode){
|
||||
|
||||
throw new Error("TransactionMessage: parsing for mal data");
|
||||
}
|
||||
|
||||
transactions = new ArrayList<TransactionData>();
|
||||
int size = paramsList.getList().size();
|
||||
for (int i = 1; i < size; ++i){
|
||||
|
||||
RLPList rlpTxData = (RLPList) paramsList.getElement(i);
|
||||
TransactionData tx = new TransactionData(rlpTxData);
|
||||
transactions.add(tx);
|
||||
}
|
||||
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
public List<TransactionData> getTransactions() {
|
||||
|
||||
if (!parsed) parseRLP();
|
||||
return transactions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getPayload() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
|
||||
if(!parsed)parseRLP();
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
for (TransactionData transactionData : transactions){
|
||||
|
||||
sb.append(" ").append(transactionData).append("\n");
|
||||
}
|
||||
|
||||
return "Transactions Message [\n" + sb.toString() + " ]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package org.ethereum.net.rlp;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 21/04/14 16:28
|
||||
*/
|
||||
public interface RLPElement {
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package org.ethereum.net.rlp;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 21/04/14 16:26
|
||||
*/
|
||||
public class RLPItem implements RLPElement{
|
||||
|
||||
byte[] data;
|
||||
|
||||
public RLPItem(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
|
||||
if (data.length == 0) return null;
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package org.ethereum.net.rlp;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.ethereum.util.Utils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 21/04/14 16:26
|
||||
*/
|
||||
public class RLPList implements RLPElement{
|
||||
|
||||
byte[] rlpData;
|
||||
List<RLPElement> list;
|
||||
|
||||
|
||||
public RLPList() {
|
||||
this.list = new ArrayList<RLPElement>();
|
||||
}
|
||||
|
||||
public void addItem(RLPElement element){
|
||||
|
||||
list.add(element);
|
||||
}
|
||||
|
||||
public RLPElement getElement(int index){
|
||||
|
||||
return list.get(index);
|
||||
}
|
||||
|
||||
public int size(){
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public List<RLPElement> getList(){
|
||||
return list;
|
||||
}
|
||||
|
||||
public void setRLPData(byte[] rlpData){
|
||||
this.rlpData = rlpData;
|
||||
}
|
||||
|
||||
|
||||
public byte[] getRLPData(){
|
||||
|
||||
return rlpData;
|
||||
}
|
||||
|
||||
|
||||
public static void recursivePrint(RLPElement element){
|
||||
|
||||
if (element == null) throw new Error("RLPElement object can't be null");
|
||||
if (element instanceof RLPList){
|
||||
|
||||
RLPList rlpList = (RLPList)element;
|
||||
System.out.print("[");
|
||||
for (RLPElement singleElement : rlpList.getList()){
|
||||
|
||||
recursivePrint(singleElement);
|
||||
}
|
||||
System.out.print("]");
|
||||
} else {
|
||||
|
||||
String hex = Utils.toHexString(((RLPItem) element).getData());
|
||||
|
||||
System.out.print(hex + ", ");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
package org.ethereum.net.vo;
|
||||
|
||||
import org.ethereum.net.rlp.RLPElement;
|
||||
import org.ethereum.net.rlp.RLPItem;
|
||||
import org.ethereum.net.rlp.RLPList;
|
||||
import org.ethereum.util.Utils;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 13/04/14 19:34
|
||||
*/
|
||||
public class BlockData {
|
||||
|
||||
RLPList rawData;
|
||||
boolean parsed = false;
|
||||
|
||||
private byte[] hash;
|
||||
private byte[] parentHash;
|
||||
private byte[] unclesHash;
|
||||
private byte[] coinbase;
|
||||
private byte[] stateHash;
|
||||
private byte[] txListHash;
|
||||
private byte[] difficulty;
|
||||
|
||||
private long timestamp;
|
||||
private byte[] extraData;
|
||||
private byte[] nonce;
|
||||
|
||||
List<TransactionData> transactionsList = new ArrayList<TransactionData>();
|
||||
List<BlockData> uncleList = new ArrayList<BlockData>();
|
||||
|
||||
public BlockData(RLPList rawData) {
|
||||
this.rawData = rawData;
|
||||
this.parsed = false;
|
||||
}
|
||||
|
||||
public BlockData(byte[] parentHash, byte[] unclesHash, byte[] coinbase, byte[] stateHash, byte[] txListHash, byte[] difficulty, long timestamp, byte[] extraData, byte[] nonce, List<TransactionData> transactionsList, List uncleList) {
|
||||
this.parentHash = parentHash;
|
||||
this.unclesHash = unclesHash;
|
||||
this.coinbase = coinbase;
|
||||
this.stateHash = stateHash;
|
||||
this.txListHash = txListHash;
|
||||
this.difficulty = difficulty;
|
||||
this.timestamp = timestamp;
|
||||
this.extraData = extraData;
|
||||
this.nonce = nonce;
|
||||
this.transactionsList = transactionsList;
|
||||
this.uncleList = uncleList;
|
||||
this.parsed = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// [parent_hash, uncles_hash, coinbase, state_root, tx_list_hash, difficulty, timestamp, extradata, nonce]
|
||||
private void parseRLP(){
|
||||
|
||||
this.hash = Utils.sha3(rawData.getRLPData());
|
||||
|
||||
List params = ((RLPList) rawData.getElement(0)).getList();
|
||||
|
||||
this.parentHash = ((RLPItem) params.get(0)).getData();
|
||||
this.unclesHash = ((RLPItem) params.get(1)).getData();
|
||||
this.coinbase = ((RLPItem) params.get(2)).getData();
|
||||
this.stateHash = ((RLPItem) params.get(3)).getData();
|
||||
this.txListHash = ((RLPItem) params.get(4)).getData();
|
||||
this.difficulty = ((RLPItem) params.get(5)).getData();
|
||||
|
||||
byte[] tsBytes = ((RLPItem) params.get(6)).getData();
|
||||
this.timestamp = (new BigInteger(tsBytes)).longValue();
|
||||
this.extraData = ((RLPItem) params.get(7)).getData();
|
||||
this.nonce = ((RLPItem) params.get(8)).getData();
|
||||
|
||||
|
||||
// parse transactions
|
||||
List<RLPElement> transactions = ((RLPList) rawData.getElement(1)).getList();
|
||||
|
||||
for (RLPElement rlpTx : transactions){
|
||||
|
||||
TransactionData tx = new TransactionData((RLPList)rlpTx);
|
||||
this.transactionsList.add(tx);
|
||||
}
|
||||
|
||||
// parse uncles
|
||||
List<RLPElement> uncleBlocks = ((RLPList) rawData.getElement(2)).getList();
|
||||
for (RLPElement rawUncle : uncleBlocks){
|
||||
|
||||
BlockData blockData = new BlockData((RLPList)rawUncle);
|
||||
this.uncleList.add(blockData);
|
||||
}
|
||||
|
||||
this.parsed = true;
|
||||
}
|
||||
|
||||
public byte[] getHash(){
|
||||
|
||||
if (!parsed) parseRLP();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public byte[] getParentHash() {
|
||||
if (!parsed) parseRLP();
|
||||
return parentHash;
|
||||
}
|
||||
|
||||
public byte[] getUnclesHash() {
|
||||
if (!parsed) parseRLP();
|
||||
return unclesHash;
|
||||
}
|
||||
|
||||
public byte[] getCoinbase() {
|
||||
if (!parsed) parseRLP();
|
||||
return coinbase;
|
||||
}
|
||||
|
||||
public byte[] getStateHash() {
|
||||
if (!parsed) parseRLP();
|
||||
return stateHash;
|
||||
}
|
||||
|
||||
public byte[] getTxListHash() {
|
||||
if (!parsed) parseRLP();
|
||||
return txListHash;
|
||||
}
|
||||
|
||||
public byte[] getDifficulty() {
|
||||
if (!parsed) parseRLP();
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
if (!parsed) parseRLP();
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public byte[] getExtraData() {
|
||||
if (!parsed) parseRLP();
|
||||
return extraData;
|
||||
}
|
||||
|
||||
public byte[] getNonce() {
|
||||
if (!parsed) parseRLP();
|
||||
return nonce;
|
||||
}
|
||||
|
||||
public List<TransactionData> getTransactionsList() {
|
||||
if (!parsed) parseRLP();
|
||||
return transactionsList;
|
||||
}
|
||||
|
||||
public List<BlockData> getUncleList() {
|
||||
if (!parsed) parseRLP();
|
||||
return uncleList;
|
||||
}
|
||||
|
||||
// [parent_hash, uncles_hash, coinbase, state_root, tx_list_hash, difficulty, timestamp, extradata, nonce]
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (!parsed) parseRLP();
|
||||
|
||||
return "BlockData [" + " hash=" + Utils.toHexString(hash) +
|
||||
" parentHash=" + Utils.toHexString(parentHash) +
|
||||
", unclesHash=" + Utils.toHexString(unclesHash) +
|
||||
", coinbase=" + Utils.toHexString(coinbase) +
|
||||
", stateHash=" + Utils.toHexString(stateHash) +
|
||||
", txListHash=" + Utils.toHexString(txListHash) +
|
||||
", difficulty=" + Utils.toHexString(difficulty) +
|
||||
", timestamp=" + timestamp +
|
||||
", extraData=" + Utils.toHexString(extraData) +
|
||||
", nonce=" + Utils.toHexString(nonce) +
|
||||
']';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package org.ethereum.net.vo;
|
||||
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.ethereum.net.rlp.RLPList;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 13/04/14 17:36
|
||||
*/
|
||||
public class PeerData {
|
||||
|
||||
RLPList rawData;
|
||||
boolean parsed = false;
|
||||
|
||||
byte[] ip;
|
||||
short port;
|
||||
byte[] peerId;
|
||||
|
||||
transient boolean isOnline = false;
|
||||
transient long lastCheckTime = 0;
|
||||
|
||||
public PeerData(RLPList rlpList){
|
||||
rawData = rlpList;
|
||||
parsed = false;
|
||||
}
|
||||
|
||||
public PeerData(byte[] ip, short port, byte[] peerId) {
|
||||
this.ip = ip;
|
||||
this.port = port;
|
||||
this.peerId = peerId;
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
public InetAddress getInetAddress(){
|
||||
|
||||
InetAddress addr = null;
|
||||
|
||||
try {
|
||||
addr = InetAddress.getByAddress(ip);
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
throw new Error("malformed ip");
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
public byte[] getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public short getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public byte[] getPeerId() {
|
||||
return peerId;
|
||||
}
|
||||
|
||||
public boolean isOnline() {
|
||||
return isOnline;
|
||||
}
|
||||
|
||||
public void setOnline(boolean online) {
|
||||
isOnline = online;
|
||||
}
|
||||
|
||||
public long getLastCheckTime() {
|
||||
return lastCheckTime;
|
||||
}
|
||||
|
||||
public void setLastCheckTime(long lastCheckTime) {
|
||||
this.lastCheckTime = lastCheckTime;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Peer: [ ip=" + getInetAddress()+ ", port=" + getPort() + ", peerId=" + Hex.toHexString( getPeerId() ) + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
PeerData peerData2 = (PeerData)obj;
|
||||
return this.getInetAddress().equals(peerData2.getInetAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getInetAddress().hashCode();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
package org.ethereum.net.vo;
|
||||
|
||||
import org.ethereum.net.rlp.RLPItem;
|
||||
import org.ethereum.net.rlp.RLPList;
|
||||
import org.ethereum.util.Utils;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 21/04/14 09:19
|
||||
*/
|
||||
public class TransactionData {
|
||||
|
||||
RLPList rawData;
|
||||
boolean parsed = false;
|
||||
|
||||
|
||||
// creation contract tx or simple send tx
|
||||
// [ nonce, value, receiveAddress, gasPrice, gasDeposit, data, signatureV, signatureR, signatureS ]
|
||||
// or
|
||||
// [ nonce, endowment, 0, gasPrice, gasDeposit (for init), body, init, signatureV, signatureR, signatureS ]
|
||||
|
||||
byte[] hash;
|
||||
byte[] nonce;
|
||||
byte[] value;
|
||||
|
||||
// In creation transaction the receive address is - 0
|
||||
byte[] receiveAddress;
|
||||
byte[] gasPrice;
|
||||
byte[] gas;
|
||||
|
||||
// Contract creation [data] will hold the contract
|
||||
// for other transaction [data] can hold data
|
||||
byte[] data;
|
||||
byte[] init;
|
||||
|
||||
|
||||
// Signature
|
||||
byte signatureV;
|
||||
byte[] signatureR;
|
||||
byte[] signatureS;
|
||||
|
||||
|
||||
public TransactionData(RLPList rawData) {
|
||||
this.rawData = rawData;
|
||||
parsed = false;
|
||||
}
|
||||
|
||||
public TransactionData(byte[] nonce, byte[] value, byte[] recieveAddress, byte[] gasPrice, byte[] gas, byte[] data, byte signatureV, byte[] signatureR, byte[] signatureS) {
|
||||
this.nonce = nonce;
|
||||
this.value = value;
|
||||
this.receiveAddress = recieveAddress;
|
||||
this.gasPrice = gasPrice;
|
||||
this.gas = gas;
|
||||
this.data = data;
|
||||
this.signatureV = signatureV;
|
||||
this.signatureR = signatureR;
|
||||
this.signatureS = signatureS;
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
|
||||
public void rlpParse(){
|
||||
|
||||
if (rawData.size() == 9){ // Simple transaction
|
||||
|
||||
this.hash = Utils.sha3(rawData.getRLPData());
|
||||
this.nonce = ((RLPItem) rawData.getElement(0)).getData();
|
||||
this.value = ((RLPItem) rawData.getElement(1)).getData();
|
||||
this.receiveAddress = ((RLPItem) rawData.getElement(2)).getData();
|
||||
this.gasPrice = ((RLPItem) rawData.getElement(3)).getData();
|
||||
this.gas = ((RLPItem) rawData.getElement(4)).getData();
|
||||
this.data = ((RLPItem) rawData.getElement(5)).getData();
|
||||
this.signatureV = ((RLPItem) rawData.getElement(6)).getData()[0];
|
||||
this.signatureR = ((RLPItem) rawData.getElement(7)).getData();
|
||||
this.signatureS = ((RLPItem) rawData.getElement(8)).getData();
|
||||
|
||||
} else if (rawData.size() == 10){ // Contract creation transaction
|
||||
|
||||
this.hash = Utils.sha3(rawData.getRLPData());
|
||||
this.nonce = ((RLPItem) rawData.getElement(0)).getData();
|
||||
this.value = ((RLPItem) rawData.getElement(1)).getData();
|
||||
this.receiveAddress = ((RLPItem) rawData.getElement(2)).getData();
|
||||
this.gasPrice = ((RLPItem) rawData.getElement(3)).getData();
|
||||
this.gas = ((RLPItem) rawData.getElement(4)).getData();
|
||||
this.data = ((RLPItem) rawData.getElement(5)).getData();
|
||||
this.init = ((RLPItem) rawData.getElement(6)).getData();
|
||||
this.signatureV = ((RLPItem) rawData.getElement(7)).getData()[0];
|
||||
this.signatureR = ((RLPItem) rawData.getElement(8)).getData();
|
||||
this.signatureS = ((RLPItem) rawData.getElement(9)).getData();
|
||||
|
||||
} else throw new Error("Wrong tx data element list size");
|
||||
|
||||
this.parsed = true;
|
||||
}
|
||||
|
||||
|
||||
public RLPList getRawData() {
|
||||
return rawData;
|
||||
}
|
||||
|
||||
public boolean isParsed() {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
public byte[] getHash() {
|
||||
if (!parsed) rlpParse();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public byte[] getNonce() {
|
||||
|
||||
if (!parsed) rlpParse();
|
||||
return nonce;
|
||||
}
|
||||
|
||||
public byte[] getValue() {
|
||||
|
||||
if (!parsed) rlpParse();
|
||||
return value;
|
||||
}
|
||||
|
||||
public byte[] getReceiveAddress() {
|
||||
|
||||
if (!parsed) rlpParse();
|
||||
return receiveAddress;
|
||||
}
|
||||
|
||||
public byte[] getGasPrice() {
|
||||
|
||||
if (!parsed) rlpParse();
|
||||
return gasPrice;
|
||||
}
|
||||
|
||||
public byte[] getGas() {
|
||||
|
||||
if (!parsed) rlpParse();
|
||||
return gas;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
|
||||
if (!parsed) rlpParse();
|
||||
return data;
|
||||
}
|
||||
|
||||
public byte[] getInit() {
|
||||
|
||||
if (!parsed) rlpParse();
|
||||
return init;
|
||||
}
|
||||
|
||||
public byte getSignatureV() {
|
||||
|
||||
if (!parsed) rlpParse();
|
||||
return signatureV;
|
||||
}
|
||||
|
||||
public byte[] getSignatureR() {
|
||||
|
||||
if (!parsed) rlpParse();
|
||||
return signatureR;
|
||||
}
|
||||
|
||||
public byte[] getSignatureS() {
|
||||
|
||||
if (!parsed) rlpParse();
|
||||
return signatureS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (!parsed) rlpParse();
|
||||
return "TransactionData [" + " hash=" + Utils.toHexString(hash) +
|
||||
" nonce=" + Utils.toHexString(nonce) +
|
||||
", value=" + Utils.toHexString(value) +
|
||||
", receiveAddress=" + Utils.toHexString(receiveAddress) +
|
||||
", gasPrice=" + Utils.toHexString(gasPrice) +
|
||||
", gas=" + Utils.toHexString(gas) +
|
||||
", data=" + Utils.toHexString(data) +
|
||||
", init=" + Utils.toHexString(init) +
|
||||
", signatureV=" + signatureV +
|
||||
", signatureR=" + Utils.toHexString(signatureR) +
|
||||
", signatureS=" + Utils.toHexString(signatureS) +
|
||||
']';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package org.ethereum.serpent;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 25/04/14 17:06
|
||||
*/
|
||||
public class GenParser {
|
||||
|
||||
|
||||
|
||||
public static void main(String args[]){
|
||||
|
||||
String userDir = System.getProperty("user.dir");
|
||||
org.antlr.Tool.main(new String[]{userDir + "\\src\\main\\java\\org\\ethereum\\serpent\\Serpent.g"});
|
||||
// org.antlr.Tool.main(new String[]{userDir + "\\src\\main\\java\\samples\\antlr\\PyEsque.g"});
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
/*******************************************************************************
|
||||
* Ethereum high level language grammar definition
|
||||
*******************************************************************************/
|
||||
grammar Serpent;
|
||||
|
||||
options {
|
||||
//language = Java;
|
||||
//output = AST;
|
||||
output = template;
|
||||
}
|
||||
|
||||
@header {
|
||||
|
||||
/* (!!!) Do not update this file manually ,
|
||||
* It was auto generated from the Serpent.g
|
||||
* grammar file.
|
||||
*/
|
||||
package org.ethereum.serpent;
|
||||
import org.ethereum.util.Utils;
|
||||
}
|
||||
|
||||
@lexer::header {
|
||||
|
||||
/* (!!!) Do not update this file manually ,
|
||||
* It was auto generated from the Serpent.g
|
||||
* grammar file.
|
||||
*/
|
||||
package org.ethereum.serpent;
|
||||
}
|
||||
|
||||
|
||||
@members {
|
||||
private java.util.ArrayList<String> globals = new java.util.ArrayList<String>();
|
||||
private int labelIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
program
|
||||
: gen_body
|
||||
{
|
||||
String conVars = "";
|
||||
|
||||
if (globals.size() > 0){
|
||||
|
||||
conVars = "0 " + (globals.size() * 32 - 1) + " MSTORE8";
|
||||
}
|
||||
}
|
||||
-> concat(left={conVars}, right={$gen_body.st})
|
||||
;
|
||||
|
||||
test_1
|
||||
:
|
||||
(
|
||||
set_var -> concat(left={$test_1.st}, right={$set_var.st})
|
||||
| get_var -> concat(left={$test_1.st}, right={$get_var.st}) )*
|
||||
;
|
||||
|
||||
/*
|
||||
test_2
|
||||
:
|
||||
(
|
||||
set_var -> concat(left={$test_2.st}, right={$set_var.st})
|
||||
)*
|
||||
|
||||
(
|
||||
if_stmt -> concat(left={$test_2.st}, right={$if_stmt.st})
|
||||
| if_else_stmt -> concat(left={$test_2.st}, right={$if_else_stmt.st})
|
||||
)
|
||||
;
|
||||
*/
|
||||
|
||||
|
||||
|
||||
gen_body
|
||||
:
|
||||
(
|
||||
set_var -> concat(left={$gen_body.st}, right={$set_var.st})
|
||||
| storage_save -> concat(left={$gen_body.st}, right={$storage_save.st})
|
||||
| return_stmt -> concat(left={$gen_body.st}, right={$return_stmt.st})
|
||||
)* ( if_else_stmt -> concat(left={$gen_body.st}, right={$if_else_stmt.st}))?
|
||||
|
||||
;
|
||||
|
||||
|
||||
|
||||
|
||||
// [if a==10:\n b=20 \n]
|
||||
// [10, 0, 'MLOAD', 'EQ', 'NOT', 'REF_0', 'JUMPI', 20, 32, 'MSTORE', 'LABEL_0']
|
||||
if_stmt
|
||||
:
|
||||
'if' unr_expr ':' gen_body
|
||||
// (!!!)RECURSION ON if_stmt ( 'elif' cond_expr ':' elif_body=set_var )*
|
||||
-> ifStmt(cond={$unr_expr.st}, body={$gen_body.st}, index={labelIndex++})
|
||||
;
|
||||
|
||||
|
||||
// [if a==10:\n b=20 \nelse: \n b=30]
|
||||
// [10, 0, 'MLOAD', 'EQ', 'NOT', 'REF_1', 'JUMPI', 20, 32, 'MSTORE', 'REF_0', 'JUMP', 'LABEL_1', 30, 32, 'MSTORE', 'LABEL_0']
|
||||
// a 10 EQ NOT REF_01 JUMPI 30 0 MSTORE REF_0 JUMP LABEL_01 20 0 MSTORE LABEL_0
|
||||
|
||||
if_else_stmt
|
||||
:
|
||||
'if' unr_expr ':' if_body=gen_body
|
||||
// (!!!)RECURSION ON if_stmt ( 'elif' unr_expr ':' elif_body=set_var )*
|
||||
'else' ':' else_body=gen_body -> ifElseStmt(cond={$unr_expr.st}, if_body={$if_body.st},
|
||||
else_body={$else_body.st}, if_index={labelIndex++}, else_index={labelIndex++}) ;
|
||||
|
||||
|
||||
|
||||
|
||||
// [multi_set_var] (a=set_var->compile(left={$program.st}, right={$a.st}))*
|
||||
set_var
|
||||
:
|
||||
{int varIndex = -1;}
|
||||
(a=var { // TODO: change it from atom to something else
|
||||
|
||||
// check if that variable already defined
|
||||
// if it didn't add it to list
|
||||
// if it did use the index * 32 for memory address
|
||||
varIndex = globals.indexOf($a.st.toString());
|
||||
if (varIndex == -1 ) {globals.add($a.st.toString()); varIndex = globals.size() - 1; }
|
||||
}
|
||||
|
||||
'=' b=bin_expr) -> set_var(param_a={$b.st}, param_b={32 * varIndex})
|
||||
;
|
||||
|
||||
get_var
|
||||
:
|
||||
{int varIndex = -1;}
|
||||
(a=var {
|
||||
|
||||
// If there is no such var throw exception
|
||||
varIndex = globals.indexOf($a.st.toString());
|
||||
if (varIndex == -1 ) {
|
||||
Error err = new Error("var undefined: " + $a.st.toString());
|
||||
throw err;
|
||||
}
|
||||
;}
|
||||
|
||||
-> get_var(varIndex={32 * varIndex})
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
unr_expr
|
||||
:
|
||||
{boolean negative = false;}
|
||||
('!' {negative = !negative;} )* a=cond_expr -> not(param={negative? $a.st : $a.st + " NOT"})
|
||||
|
||||
;
|
||||
|
||||
|
||||
cond_expr
|
||||
: a=bin_expr
|
||||
(
|
||||
'==' b=bin_expr -> equals(left={$a.st},right={$b.st}) |
|
||||
'<' b=bin_expr -> lessThan(left={$a.st},right={$b.st}) |
|
||||
'<=' b=bin_expr -> lessEqThan(left={$a.st},right={$b.st}) |
|
||||
'>=' b=bin_expr -> greatEqThan(left={$a.st},right={$b.st}) |
|
||||
'>' b=bin_expr -> greatThan(left={$a.st},right={$b.st})
|
||||
|
||||
| -> {$a.st}
|
||||
)
|
||||
;
|
||||
|
||||
storage_save
|
||||
: 'contract.storage['index=bin_expr']' '=' assignment=bin_expr -> ssave(index={$index.st}, data={$assignment.st})
|
||||
;
|
||||
|
||||
bin_expr
|
||||
: (a=atom -> {$a.st})
|
||||
(( '+' b=atom -> add(left={$bin_expr.st}, right={$b.st}) |
|
||||
'-' b=atom -> sub(left={$bin_expr.st}, right={$b.st}) |
|
||||
'*' b=atom -> mul(left={$bin_expr.st}, right={$b.st}) |
|
||||
'/' b=atom -> div(left={$bin_expr.st}, right={$b.st}) |
|
||||
'^' b=atom -> exp(left={$bin_expr.st}, right={$b.st}) |
|
||||
'%' b=atom -> mod(left={$bin_expr.st}, right={$b.st}) |
|
||||
'#/' b=atom -> sdiv(left={$bin_expr.st}, right={$b.st}) |
|
||||
'#%' b=atom -> smod(left={$bin_expr.st}, right={$b.st})
|
||||
)*)
|
||||
;
|
||||
|
||||
// "if !a==10:\n b=20 \nelse: \n b=30"
|
||||
|
||||
atom
|
||||
:
|
||||
storage_load -> iconst(value={$storage_load.st})
|
||||
| msg_sender -> iconst(value={$msg_sender.st})
|
||||
| msg_datasize -> iconst(value={$msg_datasize.st})
|
||||
| msg_load -> iconst(value={$msg_load.st})
|
||||
| get_var -> iconst(value={$get_var.st})
|
||||
| INTEGER -> iconst(value={$INTEGER.text})
|
||||
| hex_num -> iconst(value={$hex_num.st})
|
||||
|
||||
;
|
||||
|
||||
hex_num
|
||||
:
|
||||
HEX_NUMBER
|
||||
{
|
||||
String dec_num = Utils.hexStringToDecimalString($HEX_NUMBER.text);
|
||||
}
|
||||
-> iconst(value={dec_num})
|
||||
;
|
||||
|
||||
var
|
||||
: IDENT -> refVar(id={$IDENT.text} )
|
||||
;
|
||||
|
||||
storage_load
|
||||
: 'contract.storage['bin_expr']' -> sload(index={$bin_expr.st})
|
||||
;
|
||||
|
||||
msg_load
|
||||
: 'msg.data['bin_expr']' -> calldataload(index={$bin_expr.st})
|
||||
;
|
||||
|
||||
msg_sender
|
||||
: 'msg.sender' -> msdSender()
|
||||
;
|
||||
|
||||
msg_datasize
|
||||
: 'msg.datasize' -> msgDatasize()
|
||||
;
|
||||
|
||||
return_stmt
|
||||
: 'return('bin_expr')' -> returnStmt(index={$bin_expr.st})
|
||||
;
|
||||
|
||||
|
||||
fragment LETTER : ('a'..'z' | 'A'..'Z') ;
|
||||
fragment DIGIT : '0'..'9';
|
||||
INTEGER : DIGIT+ ;
|
||||
IDENT : LETTER (LETTER | DIGIT)*;
|
||||
|
||||
fragment HEX_DIGIT : ('0'..'9' | 'a'..'f' | 'A'..'F');
|
||||
HEX_NUMBER : ('0x' | '0X' )HEX_DIGIT+;
|
||||
|
||||
WS : (' ' | '\t' | '\n' | '\r' | '\f')+ {$channel = HIDDEN;};
|
||||
COMMENT : '//' .* ('\n'|'\r') {$channel = HIDDEN;};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
group Serpent2Asm;
|
||||
/** https://github.com/rollxx/antlr-php-runtime/blob/master/examples/cminus/Bytecode.stg */
|
||||
|
||||
|
||||
// [10, 0, 'MLOAD', 'EQ', 'NOT', 'REF_0', 'JUMPI', 20, 32, 'MSTORE', 'LABEL_0']
|
||||
ifStmt(cond, body, index) ::=<<
|
||||
<cond> NOT REF_<index> JUMPI <body> LABEL_<index>
|
||||
>>
|
||||
|
||||
// [10, 0, MLOAD, EQ, NOT, REF_1, JUMPI, 20, 32, MSTORE, REF_0, JUMP, LABEL_1, 30, 32, MSTORE, LABEL_0]
|
||||
ifElseStmt(cond, if_body, else_body, if_index, else_index) ::=<<
|
||||
<cond> NOT REF_<if_index> JUMPI <else_body> REF_<else_index> JUMP LABEL_<if_index> <if_body> LABEL_<else_index>
|
||||
>>
|
||||
|
||||
|
||||
set_var(param_a, param_b) ::= <<
|
||||
<param_a> <param_b> MSTORE
|
||||
>>
|
||||
|
||||
get_var(varIndex) ::= <<
|
||||
<varIndex> MLOAD
|
||||
>>
|
||||
|
||||
|
||||
compile(left, right) ::= <<
|
||||
<left> <right>
|
||||
>>
|
||||
|
||||
add(left,right) ::= <<
|
||||
<left> <right> ADD
|
||||
>>
|
||||
|
||||
sub(left,right) ::= <<
|
||||
<left> <right> SUB
|
||||
>>
|
||||
|
||||
mul(left,right) ::= <<
|
||||
<left> <right> MUL
|
||||
>>
|
||||
|
||||
div(left,right) ::= <<
|
||||
<left> <right> DIV
|
||||
>>
|
||||
|
||||
exp(left,right) ::= <<
|
||||
<left> <right> EXP
|
||||
>>
|
||||
|
||||
mod(left,right) ::= <<
|
||||
<left> <right> MOD
|
||||
>>
|
||||
|
||||
sdiv(left,right) ::= <<
|
||||
<left> <right> SDIV
|
||||
>>
|
||||
|
||||
smod(left,right) ::= <<
|
||||
<left> <right> SMOD
|
||||
>>
|
||||
|
||||
equals(left,right) ::= <<
|
||||
<left> <right> EQ
|
||||
>>
|
||||
|
||||
lessThan(left,right) ::= <<
|
||||
<left> <right> LT
|
||||
>>
|
||||
|
||||
lessEqThan(left,right) ::= <<
|
||||
<left> <right> GT NOT
|
||||
>>
|
||||
|
||||
greatThan(left,right) ::= <<
|
||||
<left> <right> GT
|
||||
>>
|
||||
|
||||
greatEqThan(left,right) ::= <<
|
||||
<left> <right> LT NOT
|
||||
>>
|
||||
|
||||
not(param) ::= <<
|
||||
<param> NOT
|
||||
>>
|
||||
|
||||
sload(index) ::= <<
|
||||
<index> SLOAD
|
||||
>>
|
||||
|
||||
ssave(index, data) ::= <<
|
||||
<data> <index> SSTORE
|
||||
>>
|
||||
|
||||
calldataload(index) ::=<<
|
||||
<index> 32 MUL CALLDATALOAD
|
||||
>>
|
||||
|
||||
msdSender() ::=<<
|
||||
CALLER
|
||||
>>
|
||||
|
||||
msgDatasize() ::=<<
|
||||
32 CALLDATASIZE DIV
|
||||
>>
|
||||
|
||||
returnStmt(index) ::= <<
|
||||
<index> MSIZE SWAP MSIZE MSTORE 32 SWAP RETURN
|
||||
>>
|
||||
|
||||
|
||||
concat(left, right) ::= <<
|
||||
<left> <right>
|
||||
>>
|
||||
|
||||
|
||||
refVar(id) ::= "<id>"
|
||||
iconst(value) ::= "<value>"
|
|
@ -0,0 +1,43 @@
|
|||
package org.ethereum.serpent;
|
||||
|
||||
import org.antlr.runtime.ANTLRStringStream;
|
||||
import org.antlr.runtime.CharStream;
|
||||
import org.antlr.runtime.CommonTokenStream;
|
||||
import org.antlr.runtime.RecognitionException;
|
||||
import org.antlr.stringtemplate.StringTemplateGroup;
|
||||
import org.antlr.stringtemplate.language.AngleBracketTemplateLexer;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 29/04/14 12:34
|
||||
*/
|
||||
public class SerpentCompiler{
|
||||
|
||||
public static String compile(String code) throws FileNotFoundException, RecognitionException {
|
||||
|
||||
CharStream stream =
|
||||
new ANTLRStringStream(code);
|
||||
|
||||
SerpentLexer lex = new SerpentLexer(stream);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lex);
|
||||
SerpentParser parser = new SerpentParser(tokens);
|
||||
|
||||
|
||||
String userDir = System.getProperty("user.dir");
|
||||
String templateFileName = userDir + "\\src\\main\\java\\org\\ethereum\\serpent\\Serpent2Asm.stg";
|
||||
|
||||
StringTemplateGroup template = new StringTemplateGroup(new FileReader(templateFileName),
|
||||
AngleBracketTemplateLexer.class);
|
||||
parser.setTemplateLib(template);
|
||||
|
||||
SerpentParser.program_return retVal = parser.program();
|
||||
|
||||
|
||||
|
||||
return retVal.getTemplate().toString().trim();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
package org.ethereum.util;
|
||||
|
||||
import org.bouncycastle.asn1.sec.SECNamedCurves;
|
||||
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URL;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.Security;
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static java.lang.System.exit;
|
||||
|
||||
/**
|
||||
* www.ethereumj.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 06/04/14 13:13
|
||||
*/
|
||||
public class Utils {
|
||||
|
||||
public static byte[] hexStringToByteArr(String hexString){
|
||||
|
||||
String hexSymbols = "0123456789ABCDEF";
|
||||
|
||||
int arrSize = (int) (hexString.length() / 3);
|
||||
byte[] result = new byte[arrSize];
|
||||
|
||||
for (int i = 0; i < arrSize; ++i){
|
||||
|
||||
int digit1 = hexSymbols.indexOf( hexString.charAt(i * 3) );
|
||||
int digit2 = hexSymbols.indexOf( hexString.charAt(i * 3 + 1) );
|
||||
|
||||
result[i] = (byte) (digit1 * 16 + digit2);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static String toHexString(byte[] data){
|
||||
|
||||
if (data == null) return "null";
|
||||
else return Hex.toHexString(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hexNum should be in form '0x34fabd34....'
|
||||
* @return
|
||||
*/
|
||||
public static String hexStringToDecimalString(String hexNum){
|
||||
|
||||
boolean match = Pattern.matches("0[xX][0-9a-fA-F]+", hexNum);
|
||||
if (!match) throw new Error("The string doesn't conains hex num in form 0x.. : [" + hexNum + "]");
|
||||
|
||||
byte[] numberBytes = Hex.decode(hexNum.substring(2));
|
||||
return (new BigInteger(1, numberBytes)).toString();
|
||||
}
|
||||
|
||||
|
||||
public static void printHexStringForByte(byte data){
|
||||
|
||||
System.out.print("[");
|
||||
|
||||
String hexNum = Integer.toHexString ((int) data & 0xFF);
|
||||
if (((int) data & 0xFF) < 16) {
|
||||
hexNum = "0" + hexNum;
|
||||
}
|
||||
|
||||
System.out.print( hexNum );
|
||||
|
||||
System.out.print("]");
|
||||
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void printHexStringForByteArray(byte[] data){
|
||||
|
||||
System.out.print("[");
|
||||
for (int i = 0; i < data.length; ++i){
|
||||
|
||||
String hexNum = Integer.toHexString ((int) data[i] & 0xFF);
|
||||
if (((int) data[i] & 0xFF) < 16) {
|
||||
hexNum = "0" + hexNum;
|
||||
}
|
||||
|
||||
System.out.print( hexNum );
|
||||
System.out.print(" ");
|
||||
}
|
||||
System.out.print("]");
|
||||
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
private static MessageDigest sha3Digest = null;
|
||||
private static MessageDigest ripemd160Digest = null;
|
||||
static {
|
||||
|
||||
try{
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
ripemd160Digest = MessageDigest.getInstance("RIPEMD160", "BC");
|
||||
sha3Digest = MessageDigest.getInstance("SHA3-256", "BC");
|
||||
} catch (Throwable th){
|
||||
|
||||
th.printStackTrace();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] sha3(byte[] token){
|
||||
return sha3Digest.digest(token);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static byte[] ripemd160(byte[] token){
|
||||
|
||||
return ripemd160Digest.digest(token);
|
||||
}
|
||||
|
||||
|
||||
static X9ECParameters curvParams = SECNamedCurves.getByName("secp256k1");
|
||||
|
||||
public static byte[] privToAddress(byte[] priv){
|
||||
|
||||
/* address create howto
|
||||
|
||||
token = "cow"
|
||||
step1 = sha3(token) // generate 256 bit privkey
|
||||
step2 = privtopub(step1)[1:] // generate 512 bit pubkey with secp256k1
|
||||
step3 = sha3(step2)[12:]
|
||||
*/
|
||||
|
||||
// TODO: validity checks
|
||||
BigInteger privKey = new BigInteger(1, priv);
|
||||
|
||||
|
||||
ECPoint Q = curvParams.getG().multiply(privKey);
|
||||
byte[] pubKey = Q.getEncoded();
|
||||
|
||||
// TODO: find a performance improvement here - how to omit creation of new byte[]
|
||||
byte[] _pubKey = Arrays.copyOfRange(pubKey, 1, pubKey.length);
|
||||
|
||||
byte[] _addr = Utils.sha3(_pubKey);
|
||||
|
||||
// TODO: find a performance improvement here - how to omit creation of new byte[]
|
||||
byte[] addr = Arrays.copyOfRange(_addr, 12, _addr.length);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
public static ImageIcon getImageIcon(String resource){
|
||||
|
||||
URL imageURL = ClassLoader.getSystemResource(resource);
|
||||
ImageIcon image = new ImageIcon(imageURL);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,439 @@
|
|||
package samples;
|
||||
// ==================================================================
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* Deterministic DSA signature generation. This is a sample
|
||||
* implementation designed to illustrate how deterministic DSA
|
||||
* chooses the pseudorandom value k when signing a given message.
|
||||
* This implementation was NOT optimized or hardened against
|
||||
* side-channel leaks.
|
||||
*
|
||||
* An instance is created with a hash function name, which must be
|
||||
* supported by the underlying Java virtual machine ("SHA-1" and
|
||||
* "SHA-256" should work everywhere). The data to sign is input
|
||||
* through the {@code update()} methods. The private key is set with
|
||||
* {@link #setPrivateKey}. The signature is obtained by calling
|
||||
* {@link #sign}; alternatively, {@link #signHash} can be used to
|
||||
* sign some data that has been externally hashed. The private key
|
||||
* MUST be set before generating the signature itself, but message
|
||||
* data can be input before setting the key.
|
||||
*
|
||||
* Instances are NOT thread-safe. However, once a signature has
|
||||
* been generated, the same instance can be used again for another
|
||||
* signature; {@link #setPrivateKey} need not be called again if the
|
||||
* private key has not changed. {@link #reset} can also be called to
|
||||
* cancel previously input data. Generating a signature with {@link
|
||||
* #sign} (not {@link #signHash}) also implicitly causes a
|
||||
* reset.
|
||||
*
|
||||
* ------------------------------------------------------------------
|
||||
* Copyright (c) 2013 IETF Trust and the persons identified as
|
||||
* authors of the code. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted pursuant to, and subject to the license
|
||||
* terms contained in, the Simplified BSD License set forth in Section
|
||||
* 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
|
||||
* (http://trustee.ietf.org/license-info).
|
||||
*
|
||||
* Technical remarks and questions can be addressed to:
|
||||
* pornin@bolet.org
|
||||
* ------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public class DeterministicDSA {
|
||||
|
||||
private String macName;
|
||||
private MessageDigest dig;
|
||||
private Mac hmac;
|
||||
private BigInteger p, q, g, x;
|
||||
private int qlen, rlen, rolen, holen;
|
||||
private byte[] bx;
|
||||
|
||||
/**
|
||||
* Create an instance, using the specified hash function.
|
||||
* The name is used to obtain from the JVM an implementation
|
||||
* of the hash function and an implementation of HMAC.
|
||||
*
|
||||
* @param hashName the hash function name
|
||||
* @throws IllegalArgumentException on unsupported name
|
||||
*/
|
||||
public DeterministicDSA(String hashName)
|
||||
{
|
||||
try {
|
||||
dig = MessageDigest.getInstance(hashName);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
throw new IllegalArgumentException(nsae);
|
||||
}
|
||||
if (hashName.indexOf('-') < 0) {
|
||||
macName = "Hmac" + hashName;
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Hmac");
|
||||
int n = hashName.length();
|
||||
for (int i = 0; i < n; i ++) {
|
||||
char c = hashName.charAt(i);
|
||||
if (c != '-') {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
macName = sb.toString();
|
||||
|
||||
}
|
||||
try {
|
||||
hmac = Mac.getInstance(macName);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
throw new IllegalArgumentException(nsae);
|
||||
}
|
||||
holen = hmac.getMacLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the private key.
|
||||
*
|
||||
* @param p key parameter: field modulus
|
||||
* @param q key parameter: subgroup order
|
||||
* @param g key parameter: generator
|
||||
* @param x private key
|
||||
*/
|
||||
public void setPrivateKey(BigInteger p, BigInteger q,
|
||||
BigInteger g, BigInteger x)
|
||||
{
|
||||
/*
|
||||
* Perform some basic sanity checks. We do not
|
||||
* check primality of p or q because that would
|
||||
* be too expensive.
|
||||
*
|
||||
* We reject keys where q is longer than 999 bits,
|
||||
* because it would complicate signature encoding.
|
||||
* Normal DSA keys do not have a q longer than 256
|
||||
* bits anyway.
|
||||
*/
|
||||
if (p == null || q == null || g == null || x == null
|
||||
|| p.signum() <= 0 || q.signum() <= 0
|
||||
|| g.signum() <= 0 || x.signum() <= 0
|
||||
|| x.compareTo(q) >= 0 || q.compareTo(p) >= 0
|
||||
|| q.bitLength() > 999
|
||||
|| g.compareTo(p) >= 0 || g.bitLength() == 1
|
||||
|| g.modPow(q, p).bitLength() != 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"invalid DSA private key");
|
||||
}
|
||||
this.p = p;
|
||||
this.q = q;
|
||||
this.g = g;
|
||||
this.x = x;
|
||||
qlen = q.bitLength();
|
||||
if (q.signum() <= 0 || qlen < 8) {
|
||||
throw new IllegalArgumentException(
|
||||
"bad group order: " + q);
|
||||
|
||||
|
||||
}
|
||||
rolen = (qlen + 7) >>> 3;
|
||||
rlen = rolen * 8;
|
||||
|
||||
/*
|
||||
* Convert the private exponent (x) into a sequence
|
||||
* of octets.
|
||||
*/
|
||||
bx = int2octets(x);
|
||||
}
|
||||
|
||||
private BigInteger bits2int(byte[] in)
|
||||
{
|
||||
BigInteger v = new BigInteger(1, in);
|
||||
int vlen = in.length * 8;
|
||||
if (vlen > qlen) {
|
||||
v = v.shiftRight(vlen - qlen);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
private byte[] int2octets(BigInteger v)
|
||||
{
|
||||
byte[] out = v.toByteArray();
|
||||
if (out.length < rolen) {
|
||||
byte[] out2 = new byte[rolen];
|
||||
System.arraycopy(out, 0,
|
||||
out2, rolen - out.length,
|
||||
out.length);
|
||||
return out2;
|
||||
} else if (out.length > rolen) {
|
||||
byte[] out2 = new byte[rolen];
|
||||
System.arraycopy(out, out.length - rolen,
|
||||
out2, 0, rolen);
|
||||
return out2;
|
||||
} else {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] bits2octets(byte[] in)
|
||||
{
|
||||
BigInteger z1 = bits2int(in);
|
||||
BigInteger z2 = z1.subtract(q);
|
||||
return int2octets(z2.signum() < 0 ? z1 : z2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
|
||||
|
||||
Pornin Informational [Page 73]
|
||||
|
||||
RFC 6979 Deterministic DSA and ECDSA August 2013
|
||||
|
||||
|
||||
* Set (or reset) the secret key used for HMAC.
|
||||
*
|
||||
* @param K the new secret key
|
||||
*/
|
||||
private void setHmacKey(byte[] K)
|
||||
{
|
||||
try {
|
||||
hmac.init(new SecretKeySpec(K, macName));
|
||||
} catch (InvalidKeyException ike) {
|
||||
throw new IllegalArgumentException(ike);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the pseudorandom k for signature generation,
|
||||
* using the process specified for deterministic DSA.
|
||||
*
|
||||
* @param h1 the hashed message
|
||||
* @return the pseudorandom k to use
|
||||
*/
|
||||
private BigInteger computek(byte[] h1)
|
||||
{
|
||||
/*
|
||||
* Convert hash value into an appropriately truncated
|
||||
* and/or expanded sequence of octets. The private
|
||||
* key was already processed (into field bx[]).
|
||||
*/
|
||||
byte[] bh = bits2octets(h1);
|
||||
|
||||
/*
|
||||
* HMAC is always used with K as key.
|
||||
* Whenever K is updated, we reset the
|
||||
* current HMAC key.
|
||||
*/
|
||||
|
||||
/* step b. */
|
||||
byte[] V = new byte[holen];
|
||||
for (int i = 0; i < holen; i ++) {
|
||||
V[i] = 0x01;
|
||||
}
|
||||
|
||||
/* step c. */
|
||||
byte[] K = new byte[holen];
|
||||
setHmacKey(K);
|
||||
|
||||
/* step d. */
|
||||
hmac.update(V);
|
||||
hmac.update((byte)0x00);
|
||||
hmac.update(bx);
|
||||
hmac.update(bh);
|
||||
K = hmac.doFinal();
|
||||
setHmacKey(K);
|
||||
|
||||
/* step e. */
|
||||
hmac.update(V);
|
||||
V = hmac.doFinal();
|
||||
|
||||
/* step f. */
|
||||
hmac.update(V);
|
||||
hmac.update((byte)0x01);
|
||||
hmac.update(bx);
|
||||
hmac.update(bh);
|
||||
K = hmac.doFinal();
|
||||
setHmacKey(K);
|
||||
|
||||
/* step g. */
|
||||
hmac.update(V);
|
||||
V = hmac.doFinal();
|
||||
|
||||
/* step h. */
|
||||
byte[] T = new byte[rolen];
|
||||
for (;;) {
|
||||
/*
|
||||
* We want qlen bits, but we support only
|
||||
* hash functions with an output length
|
||||
* multiple of 8;acd hence, we will gather
|
||||
* rlen bits, i.e., rolen octets.
|
||||
*/
|
||||
int toff = 0;
|
||||
while (toff < rolen) {
|
||||
hmac.update(V);
|
||||
V = hmac.doFinal();
|
||||
int cc = Math.min(V.length,
|
||||
T.length - toff);
|
||||
System.arraycopy(V, 0, T, toff, cc);
|
||||
toff += cc;
|
||||
}
|
||||
BigInteger k = bits2int(T);
|
||||
if (k.signum() > 0 && k.compareTo(q) < 0) {
|
||||
return k;
|
||||
}
|
||||
|
||||
/*
|
||||
* k is not in the proper range; update
|
||||
* K and V, and loop.
|
||||
*/
|
||||
|
||||
hmac.update(V);
|
||||
hmac.update((byte)0x00);
|
||||
K = hmac.doFinal();
|
||||
setHmacKey(K);
|
||||
hmac.update(V);
|
||||
V = hmac.doFinal();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process one more byte of input data (message to sign).
|
||||
*
|
||||
* @param in the extra input byte
|
||||
*/
|
||||
public void update(byte in)
|
||||
{
|
||||
dig.update(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process some extra bytes of input data (message to sign).
|
||||
*
|
||||
* @param in the extra input bytes
|
||||
*/
|
||||
public void update(byte[] in)
|
||||
{
|
||||
dig.update(in, 0, in.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process some extra bytes of input data (message to sign).
|
||||
*
|
||||
* @param in the extra input buffer
|
||||
* @param off the extra input offset
|
||||
* @param len the extra input length (in bytes)
|
||||
*/
|
||||
public void update(byte[] in, int off, int len)
|
||||
{
|
||||
dig.update(in, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce the signature. {@link #setPrivateKey} MUST have
|
||||
* been called. The signature is computed over the data
|
||||
* that was input through the {@code update*()} methods.
|
||||
* This engine is then reset (made ready for a new
|
||||
* signature generation).
|
||||
*
|
||||
|
||||
|
||||
|
||||
Pornin Informational [Page 76]
|
||||
|
||||
RFC 6979 Deterministic DSA and ECDSA August 2013
|
||||
|
||||
|
||||
* @return the signature
|
||||
*/
|
||||
public byte[] sign()
|
||||
{
|
||||
return signHash(dig.digest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce the signature. {@link #setPrivateKey} MUST
|
||||
* have been called. The signature is computed over the
|
||||
* provided hash value (data is assumed to have been hashed
|
||||
* externally). The data that was input through the
|
||||
* {@code update*()} methods is ignored, but kept.
|
||||
*
|
||||
* If the hash output is longer than the subgroup order
|
||||
* (the length of q, in bits, denoted 'qlen'), then the
|
||||
* provided value {@code h1} can be truncated, provided that
|
||||
* at least qlen leading bits are preserved. In other words,
|
||||
* bit values in {@code h1} beyond the first qlen bits are
|
||||
* ignored.
|
||||
*
|
||||
* @param h1 the hash value
|
||||
* @return the signature
|
||||
*/
|
||||
public byte[] signHash(byte[] h1)
|
||||
{
|
||||
if (p == null) {
|
||||
throw new IllegalStateException(
|
||||
"no private key set");
|
||||
}
|
||||
try {
|
||||
BigInteger k = computek(h1);
|
||||
BigInteger r = g.modPow(k, p).mod(q);
|
||||
BigInteger s = k.modInverse(q).multiply(
|
||||
bits2int(h1).add(x.multiply(r)))
|
||||
.mod(q);
|
||||
|
||||
/*
|
||||
* Signature encoding: ASN.1 SEQUENCE of
|
||||
* two INTEGERs. The conditions on q
|
||||
* imply that the encoded version of r and
|
||||
* s is no longer than 127 bytes for each,
|
||||
* including DER tag and length.
|
||||
*/
|
||||
byte[] br = r.toByteArray();
|
||||
byte[] bs = s.toByteArray();
|
||||
int ulen = br.length + bs.length + 4;
|
||||
int slen = ulen + (ulen >= 128 ? 3 : 2);
|
||||
|
||||
byte[] sig = new byte[slen];
|
||||
int i = 0;
|
||||
sig[i ++] = 0x30;
|
||||
if (ulen >= 128) {
|
||||
sig[i ++] = (byte)0x81;
|
||||
sig[i ++] = (byte)ulen;
|
||||
} else {
|
||||
sig[i ++] = (byte)ulen;
|
||||
}
|
||||
sig[i ++] = 0x02;
|
||||
sig[i ++] = (byte)br.length;
|
||||
System.arraycopy(br, 0, sig, i, br.length);
|
||||
i += br.length;
|
||||
sig[i ++] = 0x02;
|
||||
sig[i ++] = (byte)bs.length;
|
||||
System.arraycopy(bs, 0, sig, i, bs.length);
|
||||
return sig;
|
||||
|
||||
} catch (ArithmeticException ae) {
|
||||
throw new IllegalArgumentException(
|
||||
"DSA error (bad key ?)", ae);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset this engine. Data input through the {@code
|
||||
* update*()} methods is discarded. The current private key,
|
||||
* if one was set, is kept unchanged.
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
dig.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================================================================
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
package samples;
|
||||
|
||||
import com.maxmind.geoip.LookupService;
|
||||
import com.maxmind.geoip.Region;
|
||||
import com.maxmind.geoip.regionName;
|
||||
import com.maxmind.geoip2.exception.GeoIp2Exception;
|
||||
import org.ethereum.net.RLP;
|
||||
import org.ethereum.util.Utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
/**
|
||||
* www.openchain.info
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 31/03/14 21:06
|
||||
*/
|
||||
public class Main1 {
|
||||
|
||||
public static void main(String args[]) throws IOException, GeoIp2Exception, URISyntaxException {
|
||||
|
||||
|
||||
try {
|
||||
|
||||
URL flagURL = ClassLoader.getSystemResource("GeoLiteCity.dat");
|
||||
File file = new File(flagURL.toURI());
|
||||
LookupService cl = new LookupService(file);
|
||||
System.out.println(cl.getLocation("110.77.217.185"));
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
System.out.println("IO Exception");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void main1(String args[]) throws IOException {
|
||||
|
||||
//22400891000000088400000043414243
|
||||
|
||||
String helloPacket = "22400891000000088400000043414243";
|
||||
String pingPacket = "224008910000000102";
|
||||
|
||||
System.out.println(helloPacket);
|
||||
|
||||
SocketChannel socketChannel = SocketChannel.open();
|
||||
socketChannel.connect(new InetSocketAddress("localhost", 20202));
|
||||
socketChannel.configureBlocking(false);
|
||||
|
||||
String helloString = "22 40 08 91 00 00 00 79 F8 77 80 0A 80 AD 45 74 " +
|
||||
"68 65 72 65 75 6D 28 2B 2B 29 2F 5A 65 72 6F 47 " +
|
||||
"6F 78 2F 76 30 2E 34 2E 31 2F 6E 63 75 72 73 65 " +
|
||||
"73 2F 4C 69 6E 75 78 2F 67 2B 2B 07 82 76 5F B8 " +
|
||||
"40 D8 D6 0C 25 80 FA 79 5C FC 03 13 EF DE BA 86 " +
|
||||
"9D 21 94 E7 9E 7C B2 B5 22 F7 82 FF A0 39 2C BB " +
|
||||
"AB 8D 1B AC 30 12 08 B1 37 E0 DE 49 98 33 4F 3B " +
|
||||
"CF 73 FA 11 7E F2 13 F8 74 17 08 9F EA F8 4C 21 " +
|
||||
"B0 22 40 08 91 00 00 00 02 C1 02 22 40 08 91 00 " +
|
||||
"00 00 26 E5 14 A0 AB 6B 9A 56 13 97 0F AA 77 1B " +
|
||||
"12 D4 49 B2 E9 BB 92 5A B7 A3 69 F0 A4 B8 6B 28 " +
|
||||
"6E 9D 54 00 99 CF 82 01 00 22 40 08 91 00 00 00 " +
|
||||
"02 C1 16 22 40 08 91 00 00 00 02 C1 01 ";
|
||||
|
||||
String getPeersString = "22 40 08 91 00 00 00 02 C1 10 ";
|
||||
|
||||
|
||||
byte[] helloBytes = hexStringToByteArr(helloString);
|
||||
|
||||
// Sending
|
||||
ByteBuffer outBuffer = ByteBuffer.allocate(helloBytes.length);
|
||||
|
||||
outBuffer.clear();
|
||||
outBuffer.put(helloBytes);
|
||||
outBuffer.flip();
|
||||
|
||||
while (outBuffer.hasRemaining()) {
|
||||
socketChannel.write(outBuffer);
|
||||
}
|
||||
|
||||
|
||||
outBuffer.clear();
|
||||
byte[] getPeersBytes = hexStringToByteArr(getPeersString);
|
||||
|
||||
// Sending
|
||||
outBuffer = ByteBuffer.allocate(getPeersBytes.length);
|
||||
|
||||
outBuffer.clear();
|
||||
outBuffer.put(getPeersBytes);
|
||||
outBuffer.flip();
|
||||
|
||||
while (outBuffer.hasRemaining()) {
|
||||
socketChannel.write(outBuffer);
|
||||
}
|
||||
|
||||
|
||||
ByteBuffer inBuffer = ByteBuffer.allocate(1);
|
||||
|
||||
int bytesRead = socketChannel.read(inBuffer); //read into buffer.
|
||||
while (bytesRead != -1) {
|
||||
|
||||
inBuffer.flip(); //make buffer ready for read
|
||||
|
||||
while (inBuffer.hasRemaining()) {
|
||||
|
||||
byte oneByte = inBuffer.get();
|
||||
|
||||
System.out.print(Integer.toHexString((int) oneByte & 0x00FF)); // read 1 byte at a time
|
||||
System.out.print(" ");
|
||||
}
|
||||
|
||||
|
||||
inBuffer.clear(); //make buffer ready for writing
|
||||
bytesRead = socketChannel.read(inBuffer);
|
||||
}
|
||||
|
||||
|
||||
// read 4 bytes sync token 0x22400891
|
||||
// read 4 bytes packet size token, translate to size
|
||||
|
||||
// read packet according the size
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static byte[] hexStringToByteArr(String hexString) {
|
||||
|
||||
String hexSymbols = "0123456789ABCDEF";
|
||||
|
||||
int arrSize = (int) (hexString.length() / 3);
|
||||
byte[] result = new byte[arrSize];
|
||||
|
||||
for (int i = 0; i < arrSize; ++i) {
|
||||
|
||||
int digit1 = hexSymbols.indexOf(hexString.charAt(i * 3));
|
||||
int digit2 = hexSymbols.indexOf(hexString.charAt(i * 3 + 1));
|
||||
|
||||
result[i] = (byte) (digit1 * 16 + digit2);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static void main2(String args[]) {
|
||||
|
||||
String helloPacket =
|
||||
"F8 77 80 0B 80 AD 45 74 68 65 72 65 75 6D 28 2B 2B 29 " +
|
||||
"2F 5A 65 72 6F 47 6F 78 2F 76 30 2E 34 2E 32 2F " +
|
||||
"6E 63 75 72 73 65 73 2F 4C 69 6E 75 78 2F 67 2B " +
|
||||
"2B 07 82 76 5F B8 40 80 7D 3E D5 E7 7C BA 05 8D " +
|
||||
"C0 55 4A E0 90 98 9E FE EA 55 33 52 B3 1A DF DB " +
|
||||
"80 5E 2A 1A 7D F7 9D 14 FE 8D 9D 2C CE AA D8 E9 " +
|
||||
"4B 09 37 47 F1 33 C3 EE F3 98 83 96 20 1D 24 17 " +
|
||||
"93 83 5D 38 70 FF D4";
|
||||
|
||||
|
||||
String peersPacket = "F8 4E 11 F8 4B C5 36 81 " +
|
||||
"CC 0A 29 82 76 5F B8 40 D8 D6 0C 25 80 FA 79 5C " +
|
||||
"FC 03 13 EF DE BA 86 9D 21 94 E7 9E 7C B2 B5 22 " +
|
||||
"F7 82 FF A0 39 2C BB AB 8D 1B AC 30 12 08 B1 37 " +
|
||||
"E0 DE 49 98 33 4F 3B CF 73 FA 11 7E F2 13 F8 74 " +
|
||||
"17 08 9F EA F8 4C 21 B0";
|
||||
|
||||
|
||||
byte[] payload = Utils.hexStringToByteArr(peersPacket);
|
||||
|
||||
Utils.printHexStringForByteArray(payload);
|
||||
|
||||
Queue<Integer> index = new LinkedList<Integer>();
|
||||
RLP.fullTraverse(payload, 0, 0, payload.length, 1, index);
|
||||
|
||||
// for (Integer item : index) System.out.println("ind --> " + item);
|
||||
|
||||
|
||||
// Message newMessage = MessageFactory.createMessage(payload, index);
|
||||
// System.out.println(newMessage.toString());
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package samples;
|
||||
|
||||
import org.ethereum.net.client.ClientPeer;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 10/04/14 12:50
|
||||
*/
|
||||
public class Main2 {
|
||||
|
||||
|
||||
public static void main(String args[]){
|
||||
|
||||
// 66.49.191.123
|
||||
// 54.204.10.41
|
||||
// 130.88.0.226
|
||||
// 85.65.126.45
|
||||
// 54.72.31.55
|
||||
|
||||
// new ClientPeer().connect("66.49.191.123", 30303);
|
||||
// new ClientPeer().connect("66.49.191.123", 30303);
|
||||
|
||||
// new ClientPeer().connect("54.72.31.55", 30303);
|
||||
|
||||
String ip_1 = "131.104.252.4";
|
||||
String ip_2 = "107.170.57.247";
|
||||
String ip_3 = "68.48.173.163";
|
||||
String ip_4 = "86.183.231.205";
|
||||
String ip_5 = "68.185.234.64";
|
||||
String ip_6 = "207.219.69.154";
|
||||
|
||||
|
||||
|
||||
|
||||
// new ClientPeer().connect("192.168.1.102", 30303);
|
||||
|
||||
|
||||
// new ClientPeer().connect("83.172.226.79", 30303);
|
||||
// new ClientPeer().connect("68.48.173.163", 31313);
|
||||
// new ClientPeer().connect("86.150.41.127", 30303);
|
||||
|
||||
// new ClientPeer().connect("82.217.72.169", 30303); nicksavers
|
||||
// new ClientPeer().connect("94.197.120.80", 30303); stephan (ursium)
|
||||
|
||||
|
||||
// new ClientPeer().connect("54.72.31.55", 30303); // peer discovery: capability = 4
|
||||
|
||||
new ClientPeer().connect("54.201.28.117", 30303); // poc-5
|
||||
// new ClientPeer().connect("94.210.200.192", 30303); // poc-5
|
||||
// new ClientPeer().connect("62.78.198.208", 30303); // poc-5 not stable
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* POC - 5
|
||||
|
||||
Hello: [/206.223.168.190] Canada
|
||||
Hello: [/94.210.200.192] Netherlands
|
||||
Hello: [/88.69.198.198] Germany
|
||||
Hello: [/24.157.83.122] Canada
|
||||
Hello: [/71.202.162.40] United States
|
||||
Hello: [/64.231.10.208] Canada
|
||||
Hello: [/85.65.126.45] Israel
|
||||
Hello: [/62.78.198.208] Finland
|
||||
Hello: [/50.133.12.228] United States
|
||||
Hello: [/77.166.77.107] Netherlands
|
||||
Hello: [/110.77.217.185] Thailand
|
||||
Hello: [/64.231.9.30] Canada
|
||||
Hello: [/213.100.250.57] Sweden
|
||||
Hello: [/162.243.203.121] United States
|
||||
Hello: [/82.217.72.169] Netherlands
|
||||
Hello: [/99.231.80.166] Canada
|
||||
Hello: [/131.104.252.4] Canada
|
||||
Hello: [/54.204.10.41] United States
|
||||
Hello: [/54.201.28.117] United States
|
||||
Hello: [/67.204.1.162] Canada
|
||||
Hello: [/82.240.16.5] France
|
||||
Hello: [/74.79.23.119] United States
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package samples;
|
||||
|
||||
|
||||
|
||||
import org.bouncycastle.jce.ECPointUtil;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
|
||||
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.spec.ECFieldF2m;
|
||||
import java.security.spec.EllipticCurve;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 17/04/14 09:37
|
||||
*/
|
||||
public class Main3 {
|
||||
|
||||
static private byte[] shortMsg = Hex.decode("54686520717569636B2062726F776E20666F78206A756D7073206F76657220746865206C617A7920646F67");
|
||||
|
||||
public static void main(String args[]) throws NoSuchProviderException, NoSuchAlgorithmException, IOException {
|
||||
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA3-256", "BC");
|
||||
byte[] result = digest.digest(shortMsg);
|
||||
|
||||
byte[] expected = Hex.decode("4D741B6F1EB29CB2A9B9911C82F56FA8D73B04959D3D9D222895DF6C0B28AA15");
|
||||
|
||||
if (Arrays.equals(expected, result)){
|
||||
|
||||
System.out.println("equal !!!");
|
||||
} else {
|
||||
|
||||
Hex.encode(result, System.out);
|
||||
System.out.flush();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package samples;
|
||||
|
||||
|
||||
import org.bouncycastle.jce.ECPointUtil;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.ethereum.util.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 17/04/14 09:37
|
||||
*/
|
||||
public class Main4 {
|
||||
|
||||
static private byte[] shortMsg = Hex.decode("54686520717569636B2062726F776E20666F78206A756D7073206F76657220746865206C617A7920646F67");
|
||||
|
||||
public static void main(String args[]) throws NoSuchProviderException, NoSuchAlgorithmException, IOException, InvalidKeySpecException {
|
||||
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
|
||||
EllipticCurve curve = new EllipticCurve(
|
||||
new ECFieldF2m(239, // m
|
||||
new int[] { 36 }), // k
|
||||
new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a
|
||||
new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b
|
||||
|
||||
ECParameterSpec params = new ECParameterSpec(
|
||||
curve,
|
||||
ECPointUtil.decodePoint(curve,
|
||||
Hex.decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G
|
||||
new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n
|
||||
4); // h
|
||||
|
||||
ECPrivateKeySpec priKeySpec = new ECPrivateKeySpec(
|
||||
new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d
|
||||
params);
|
||||
|
||||
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(
|
||||
ECPointUtil.decodePoint(curve, Hex.decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q
|
||||
params);
|
||||
|
||||
Signature sgr = Signature.getInstance("ECDSA", "BC");
|
||||
KeyFactory f = KeyFactory.getInstance("ECDSA", "BC");
|
||||
PrivateKey sKey = f.generatePrivate(priKeySpec);
|
||||
PublicKey vKey = f.generatePublic(pubKeySpec);
|
||||
|
||||
// System.out.println(vKey);
|
||||
|
||||
|
||||
|
||||
System.out.println(Hex.toHexString(Utils.sha3("coinbase".getBytes())));
|
||||
|
||||
// toAddress(sha3("coinbase"));
|
||||
// toAddress(76ec948a9207fdea26dcba91086bcdd181920ff52a539b0d1eb28e73b4cd92af);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package samples;
|
||||
|
||||
import org.ethereum.gui.PeersTableModel;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 25/04/14 07:11
|
||||
*/
|
||||
public class PeersTableMain extends JFrame{
|
||||
|
||||
|
||||
|
||||
// Instance attributes used in this example
|
||||
private JPanel topPanel;
|
||||
private JTable table;
|
||||
private JScrollPane scrollPane;
|
||||
|
||||
// Constructor of main frame
|
||||
public PeersTableMain()
|
||||
{
|
||||
// Set the frame characteristics
|
||||
setTitle( "Ethereum Peers" );
|
||||
setSize( 355, 300 );
|
||||
setLocation(815, 80);
|
||||
setBackground( Color.gray );
|
||||
|
||||
java.net.URL url = ClassLoader.getSystemResource("ethereum-icon.png");
|
||||
Toolkit kit = Toolkit.getDefaultToolkit();
|
||||
Image img = kit.createImage(url);
|
||||
this.setIconImage(img);
|
||||
|
||||
|
||||
// Create a panel to hold all other components
|
||||
topPanel = new JPanel();
|
||||
topPanel.setLayout( new BorderLayout() );
|
||||
getContentPane().add( topPanel );
|
||||
|
||||
|
||||
// Create a new table instance
|
||||
table = new JTable( );
|
||||
table.setModel(new PeersTableModel());
|
||||
|
||||
table.setFont(new Font("Courier New", Font.PLAIN, 18));
|
||||
table.setForeground(Color.GRAY);
|
||||
table.setTableHeader(null);
|
||||
|
||||
|
||||
TableCellRenderer tcr = table.getDefaultRenderer(String.class);
|
||||
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer)tcr;
|
||||
renderer.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
|
||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
table.setCellSelectionEnabled(true);
|
||||
|
||||
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
|
||||
table.getColumnModel().getColumn(0).setPreferredWidth(60);
|
||||
table.getColumnModel().getColumn(1).setPreferredWidth(200);
|
||||
table.getColumnModel().getColumn(2).setPreferredWidth(60);
|
||||
|
||||
table.setRowMargin(3);
|
||||
table.setRowHeight(50);
|
||||
|
||||
// Add the table to a scrolling pane
|
||||
scrollPane = new JScrollPane( table );
|
||||
topPanel.add( scrollPane, BorderLayout.CENTER );
|
||||
}
|
||||
|
||||
public static void main(String args[]){
|
||||
|
||||
PeersTableMain mainFrame = new PeersTableMain();
|
||||
mainFrame.setVisible( true );
|
||||
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package samples.antlr;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 25/04/14 17:06
|
||||
*/
|
||||
public class GenParser {
|
||||
|
||||
|
||||
public static void main(String args[]){
|
||||
|
||||
String userDir = System.getProperty("user.dir");
|
||||
String grammarFile = userDir + "\\src\\main\\java\\samples\\antlr\\Sample.g";
|
||||
org.antlr.Tool.main(new String[]{grammarFile});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
grammar PyEsque;
|
||||
|
||||
options {
|
||||
language = Java;
|
||||
output = AST;
|
||||
//output=template;
|
||||
}
|
||||
|
||||
tokens {
|
||||
BLOCK;
|
||||
}
|
||||
|
||||
@header {
|
||||
package samples.antlr;
|
||||
}
|
||||
|
||||
@lexer::header {
|
||||
package samples.antlr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@lexer::members {
|
||||
|
||||
private int previousIndents = -1;
|
||||
private int indentLevel = 0;
|
||||
java.util.Queue<Token> tokens = new java.util.LinkedList<Token>();
|
||||
|
||||
@Override
|
||||
public void emit(Token t) {
|
||||
state.token = t;
|
||||
tokens.offer(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token nextToken() {
|
||||
super.nextToken();
|
||||
return tokens.isEmpty() ? getEOFToken() : tokens.poll();
|
||||
}
|
||||
|
||||
private void jump(int ttype) {
|
||||
indentLevel += (ttype == Dedent ? -1 : 1);
|
||||
emit(new CommonToken(ttype, "level=" + indentLevel));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
parse
|
||||
: block EOF -> block
|
||||
;
|
||||
|
||||
block
|
||||
: Indent block_atoms Dedent -> ^(BLOCK block_atoms)
|
||||
;
|
||||
|
||||
block_atoms
|
||||
: (Id | block)+
|
||||
;
|
||||
|
||||
NewLine
|
||||
: NL SP?
|
||||
{
|
||||
int n = $SP.text == null ? 0 : $SP.text.length();
|
||||
if(n > previousIndents) {
|
||||
jump(Indent);
|
||||
previousIndents = n;
|
||||
}
|
||||
else if(n < previousIndents) {
|
||||
jump(Dedent);
|
||||
previousIndents = n;
|
||||
}
|
||||
else if(input.LA(1) == EOF) {
|
||||
while(indentLevel > 0) {
|
||||
jump(Dedent);
|
||||
}
|
||||
}
|
||||
else {
|
||||
skip();
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
Id
|
||||
: ('a'..'z' | 'A'..'Z')+
|
||||
;
|
||||
|
||||
SpaceChars
|
||||
: SP {skip();}
|
||||
;
|
||||
|
||||
fragment NL : '\r'? '\n' | '\r';
|
||||
fragment SP : (' ' | '\t')+;
|
||||
fragment Indent : ;
|
||||
fragment Dedent : ;
|
||||
|
||||
|
||||
expression
|
||||
: INTEGER*
|
||||
;
|
||||
|
||||
|
||||
|
||||
fragment DIGIT : '0'..'9';
|
||||
INTEGER : DIGIT+ ;
|
|
@ -0,0 +1,547 @@
|
|||
// $ANTLR 3.5.2 E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g 2014-05-01 16:36:17
|
||||
|
||||
package samples.antlr;
|
||||
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
import java.util.Stack;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public class PyEsqueLexer extends Lexer {
|
||||
public static final int EOF=-1;
|
||||
public static final int BLOCK=4;
|
||||
public static final int DIGIT=5;
|
||||
public static final int Dedent=6;
|
||||
public static final int INTEGER=7;
|
||||
public static final int Id=8;
|
||||
public static final int Indent=9;
|
||||
public static final int NL=10;
|
||||
public static final int NewLine=11;
|
||||
public static final int SP=12;
|
||||
public static final int SpaceChars=13;
|
||||
|
||||
|
||||
private int previousIndents = -1;
|
||||
private int indentLevel = 0;
|
||||
java.util.Queue<Token> tokens = new java.util.LinkedList<Token>();
|
||||
|
||||
@Override
|
||||
public void emit(Token t) {
|
||||
state.token = t;
|
||||
tokens.offer(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token nextToken() {
|
||||
super.nextToken();
|
||||
return tokens.isEmpty() ? getEOFToken() : tokens.poll();
|
||||
}
|
||||
|
||||
private void jump(int ttype) {
|
||||
indentLevel += (ttype == Dedent ? -1 : 1);
|
||||
emit(new CommonToken(ttype, "level=" + indentLevel));
|
||||
}
|
||||
|
||||
|
||||
// delegates
|
||||
// delegators
|
||||
public Lexer[] getDelegates() {
|
||||
return new Lexer[] {};
|
||||
}
|
||||
|
||||
public PyEsqueLexer() {}
|
||||
public PyEsqueLexer(CharStream input) {
|
||||
this(input, new RecognizerSharedState());
|
||||
}
|
||||
public PyEsqueLexer(CharStream input, RecognizerSharedState state) {
|
||||
super(input,state);
|
||||
}
|
||||
@Override public String getGrammarFileName() { return "E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g"; }
|
||||
|
||||
// $ANTLR start "NewLine"
|
||||
public final void mNewLine() throws RecognitionException {
|
||||
try {
|
||||
int _type = NewLine;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
CommonToken SP1=null;
|
||||
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:61:2: ( NL ( SP )? )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:61:4: NL ( SP )?
|
||||
{
|
||||
mNL();
|
||||
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:61:7: ( SP )?
|
||||
int alt1=2;
|
||||
int LA1_0 = input.LA(1);
|
||||
if ( (LA1_0=='\t'||LA1_0==' ') ) {
|
||||
alt1=1;
|
||||
}
|
||||
switch (alt1) {
|
||||
case 1 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:61:7: SP
|
||||
{
|
||||
int SP1Start39 = getCharIndex();
|
||||
int SP1StartLine39 = getLine();
|
||||
int SP1StartCharPos39 = getCharPositionInLine();
|
||||
mSP();
|
||||
SP1 = new CommonToken(input, Token.INVALID_TOKEN_TYPE, Token.DEFAULT_CHANNEL, SP1Start39, getCharIndex()-1);
|
||||
SP1.setLine(SP1StartLine39);
|
||||
SP1.setCharPositionInLine(SP1StartCharPos39);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int n = (SP1!=null?SP1.getText():null) == null ? 0 : (SP1!=null?SP1.getText():null).length();
|
||||
if(n > previousIndents) {
|
||||
jump(Indent);
|
||||
previousIndents = n;
|
||||
}
|
||||
else if(n < previousIndents) {
|
||||
jump(Dedent);
|
||||
previousIndents = n;
|
||||
}
|
||||
else if(input.LA(1) == EOF) {
|
||||
while(indentLevel > 0) {
|
||||
jump(Dedent);
|
||||
}
|
||||
}
|
||||
else {
|
||||
skip();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "NewLine"
|
||||
|
||||
// $ANTLR start "Id"
|
||||
public final void mId() throws RecognitionException {
|
||||
try {
|
||||
int _type = Id;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:85:2: ( ( 'a' .. 'z' | 'A' .. 'Z' )+ )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:85:4: ( 'a' .. 'z' | 'A' .. 'Z' )+
|
||||
{
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:85:4: ( 'a' .. 'z' | 'A' .. 'Z' )+
|
||||
int cnt2=0;
|
||||
loop2:
|
||||
while (true) {
|
||||
int alt2=2;
|
||||
int LA2_0 = input.LA(1);
|
||||
if ( ((LA2_0 >= 'A' && LA2_0 <= 'Z')||(LA2_0 >= 'a' && LA2_0 <= 'z')) ) {
|
||||
alt2=1;
|
||||
}
|
||||
|
||||
switch (alt2) {
|
||||
case 1 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:
|
||||
{
|
||||
if ( (input.LA(1) >= 'A' && input.LA(1) <= 'Z')||(input.LA(1) >= 'a' && input.LA(1) <= 'z') ) {
|
||||
input.consume();
|
||||
}
|
||||
else {
|
||||
MismatchedSetException mse = new MismatchedSetException(null,input);
|
||||
recover(mse);
|
||||
throw mse;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
if ( cnt2 >= 1 ) break loop2;
|
||||
EarlyExitException eee = new EarlyExitException(2, input);
|
||||
throw eee;
|
||||
}
|
||||
cnt2++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "Id"
|
||||
|
||||
// $ANTLR start "SpaceChars"
|
||||
public final void mSpaceChars() throws RecognitionException {
|
||||
try {
|
||||
int _type = SpaceChars;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:89:2: ( SP )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:89:4: SP
|
||||
{
|
||||
mSP();
|
||||
|
||||
skip();
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "SpaceChars"
|
||||
|
||||
// $ANTLR start "NL"
|
||||
public final void mNL() throws RecognitionException {
|
||||
try {
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:92:17: ( ( '\\r' )? '\\n' | '\\r' )
|
||||
int alt4=2;
|
||||
int LA4_0 = input.LA(1);
|
||||
if ( (LA4_0=='\r') ) {
|
||||
int LA4_1 = input.LA(2);
|
||||
if ( (LA4_1=='\n') ) {
|
||||
alt4=1;
|
||||
}
|
||||
|
||||
else {
|
||||
alt4=2;
|
||||
}
|
||||
|
||||
}
|
||||
else if ( (LA4_0=='\n') ) {
|
||||
alt4=1;
|
||||
}
|
||||
|
||||
else {
|
||||
NoViableAltException nvae =
|
||||
new NoViableAltException("", 4, 0, input);
|
||||
throw nvae;
|
||||
}
|
||||
|
||||
switch (alt4) {
|
||||
case 1 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:92:19: ( '\\r' )? '\\n'
|
||||
{
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:92:19: ( '\\r' )?
|
||||
int alt3=2;
|
||||
int LA3_0 = input.LA(1);
|
||||
if ( (LA3_0=='\r') ) {
|
||||
alt3=1;
|
||||
}
|
||||
switch (alt3) {
|
||||
case 1 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:92:19: '\\r'
|
||||
{
|
||||
match('\r');
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
match('\n');
|
||||
}
|
||||
break;
|
||||
case 2 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:92:32: '\\r'
|
||||
{
|
||||
match('\r');
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "NL"
|
||||
|
||||
// $ANTLR start "SP"
|
||||
public final void mSP() throws RecognitionException {
|
||||
try {
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:93:17: ( ( ' ' | '\\t' )+ )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:93:19: ( ' ' | '\\t' )+
|
||||
{
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:93:19: ( ' ' | '\\t' )+
|
||||
int cnt5=0;
|
||||
loop5:
|
||||
while (true) {
|
||||
int alt5=2;
|
||||
int LA5_0 = input.LA(1);
|
||||
if ( (LA5_0=='\t'||LA5_0==' ') ) {
|
||||
alt5=1;
|
||||
}
|
||||
|
||||
switch (alt5) {
|
||||
case 1 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:
|
||||
{
|
||||
if ( input.LA(1)=='\t'||input.LA(1)==' ' ) {
|
||||
input.consume();
|
||||
}
|
||||
else {
|
||||
MismatchedSetException mse = new MismatchedSetException(null,input);
|
||||
recover(mse);
|
||||
throw mse;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
if ( cnt5 >= 1 ) break loop5;
|
||||
EarlyExitException eee = new EarlyExitException(5, input);
|
||||
throw eee;
|
||||
}
|
||||
cnt5++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "SP"
|
||||
|
||||
// $ANTLR start "Indent"
|
||||
public final void mIndent() throws RecognitionException {
|
||||
try {
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:94:17: ()
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:94:19:
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "Indent"
|
||||
|
||||
// $ANTLR start "Dedent"
|
||||
public final void mDedent() throws RecognitionException {
|
||||
try {
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:95:17: ()
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:95:19:
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "Dedent"
|
||||
|
||||
// $ANTLR start "DIGIT"
|
||||
public final void mDIGIT() throws RecognitionException {
|
||||
try {
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:104:16: ( '0' .. '9' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:
|
||||
{
|
||||
if ( (input.LA(1) >= '0' && input.LA(1) <= '9') ) {
|
||||
input.consume();
|
||||
}
|
||||
else {
|
||||
MismatchedSetException mse = new MismatchedSetException(null,input);
|
||||
recover(mse);
|
||||
throw mse;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "DIGIT"
|
||||
|
||||
// $ANTLR start "INTEGER"
|
||||
public final void mINTEGER() throws RecognitionException {
|
||||
try {
|
||||
int _type = INTEGER;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:105:9: ( ( DIGIT )+ )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:105:11: ( DIGIT )+
|
||||
{
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:105:11: ( DIGIT )+
|
||||
int cnt6=0;
|
||||
loop6:
|
||||
while (true) {
|
||||
int alt6=2;
|
||||
int LA6_0 = input.LA(1);
|
||||
if ( ((LA6_0 >= '0' && LA6_0 <= '9')) ) {
|
||||
alt6=1;
|
||||
}
|
||||
|
||||
switch (alt6) {
|
||||
case 1 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:
|
||||
{
|
||||
if ( (input.LA(1) >= '0' && input.LA(1) <= '9') ) {
|
||||
input.consume();
|
||||
}
|
||||
else {
|
||||
MismatchedSetException mse = new MismatchedSetException(null,input);
|
||||
recover(mse);
|
||||
throw mse;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
if ( cnt6 >= 1 ) break loop6;
|
||||
EarlyExitException eee = new EarlyExitException(6, input);
|
||||
throw eee;
|
||||
}
|
||||
cnt6++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "INTEGER"
|
||||
|
||||
@Override
|
||||
public void mTokens() throws RecognitionException {
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:1:8: ( NewLine | Id | SpaceChars | INTEGER )
|
||||
int alt7=4;
|
||||
switch ( input.LA(1) ) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
{
|
||||
alt7=1;
|
||||
}
|
||||
break;
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'G':
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'J':
|
||||
case 'K':
|
||||
case 'L':
|
||||
case 'M':
|
||||
case 'N':
|
||||
case 'O':
|
||||
case 'P':
|
||||
case 'Q':
|
||||
case 'R':
|
||||
case 'S':
|
||||
case 'T':
|
||||
case 'U':
|
||||
case 'V':
|
||||
case 'W':
|
||||
case 'X':
|
||||
case 'Y':
|
||||
case 'Z':
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
{
|
||||
alt7=2;
|
||||
}
|
||||
break;
|
||||
case '\t':
|
||||
case ' ':
|
||||
{
|
||||
alt7=3;
|
||||
}
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
{
|
||||
alt7=4;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NoViableAltException nvae =
|
||||
new NoViableAltException("", 7, 0, input);
|
||||
throw nvae;
|
||||
}
|
||||
switch (alt7) {
|
||||
case 1 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:1:10: NewLine
|
||||
{
|
||||
mNewLine();
|
||||
|
||||
}
|
||||
break;
|
||||
case 2 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:1:18: Id
|
||||
{
|
||||
mId();
|
||||
|
||||
}
|
||||
break;
|
||||
case 3 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:1:21: SpaceChars
|
||||
{
|
||||
mSpaceChars();
|
||||
|
||||
}
|
||||
break;
|
||||
case 4 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:1:32: INTEGER
|
||||
{
|
||||
mINTEGER();
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,394 @@
|
|||
// $ANTLR 3.5.2 E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g 2014-05-01 16:36:17
|
||||
|
||||
package samples.antlr;
|
||||
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
import java.util.Stack;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.antlr.runtime.tree.*;
|
||||
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public class PyEsqueParser extends Parser {
|
||||
public static final String[] tokenNames = new String[] {
|
||||
"<invalid>", "<EOR>", "<DOWN>", "<UP>", "BLOCK", "DIGIT", "Dedent", "INTEGER",
|
||||
"Id", "Indent", "NL", "NewLine", "SP", "SpaceChars"
|
||||
};
|
||||
public static final int EOF=-1;
|
||||
public static final int BLOCK=4;
|
||||
public static final int DIGIT=5;
|
||||
public static final int Dedent=6;
|
||||
public static final int INTEGER=7;
|
||||
public static final int Id=8;
|
||||
public static final int Indent=9;
|
||||
public static final int NL=10;
|
||||
public static final int NewLine=11;
|
||||
public static final int SP=12;
|
||||
public static final int SpaceChars=13;
|
||||
|
||||
// delegates
|
||||
public Parser[] getDelegates() {
|
||||
return new Parser[] {};
|
||||
}
|
||||
|
||||
// delegators
|
||||
|
||||
|
||||
public PyEsqueParser(TokenStream input) {
|
||||
this(input, new RecognizerSharedState());
|
||||
}
|
||||
public PyEsqueParser(TokenStream input, RecognizerSharedState state) {
|
||||
super(input, state);
|
||||
}
|
||||
|
||||
protected TreeAdaptor adaptor = new CommonTreeAdaptor();
|
||||
|
||||
public void setTreeAdaptor(TreeAdaptor adaptor) {
|
||||
this.adaptor = adaptor;
|
||||
}
|
||||
public TreeAdaptor getTreeAdaptor() {
|
||||
return adaptor;
|
||||
}
|
||||
@Override public String[] getTokenNames() { return PyEsqueParser.tokenNames; }
|
||||
@Override public String getGrammarFileName() { return "E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g"; }
|
||||
|
||||
|
||||
public static class parse_return extends ParserRuleReturnScope {
|
||||
Object tree;
|
||||
@Override
|
||||
public Object getTree() { return tree; }
|
||||
};
|
||||
|
||||
|
||||
// $ANTLR start "parse"
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:48:1: parse : block EOF -> block ;
|
||||
public final parse_return parse() throws RecognitionException {
|
||||
parse_return retval = new parse_return();
|
||||
retval.start = input.LT(1);
|
||||
|
||||
Object root_0 = null;
|
||||
|
||||
Token EOF2=null;
|
||||
ParserRuleReturnScope block1 =null;
|
||||
|
||||
Object EOF2_tree=null;
|
||||
RewriteRuleTokenStream stream_EOF=new RewriteRuleTokenStream(adaptor,"token EOF");
|
||||
RewriteRuleSubtreeStream stream_block=new RewriteRuleSubtreeStream(adaptor,"rule block");
|
||||
|
||||
try {
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:49:2: ( block EOF -> block )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:49:4: block EOF
|
||||
{
|
||||
pushFollow(FOLLOW_block_in_parse74);
|
||||
block1=block();
|
||||
state._fsp--;
|
||||
|
||||
stream_block.add(block1.getTree());
|
||||
EOF2=(Token)match(input,EOF,FOLLOW_EOF_in_parse76);
|
||||
stream_EOF.add(EOF2);
|
||||
|
||||
// AST REWRITE
|
||||
// elements: block
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
// rule list labels:
|
||||
// wildcard labels:
|
||||
retval.tree = root_0;
|
||||
RewriteRuleSubtreeStream stream_retval=new RewriteRuleSubtreeStream(adaptor,"rule retval",retval!=null?retval.getTree():null);
|
||||
|
||||
root_0 = (Object)adaptor.nil();
|
||||
// 49:14: -> block
|
||||
{
|
||||
adaptor.addChild(root_0, stream_block.nextTree());
|
||||
}
|
||||
|
||||
|
||||
retval.tree = root_0;
|
||||
|
||||
}
|
||||
|
||||
retval.stop = input.LT(-1);
|
||||
|
||||
retval.tree = (Object)adaptor.rulePostProcessing(root_0);
|
||||
adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop);
|
||||
|
||||
}
|
||||
catch (RecognitionException re) {
|
||||
reportError(re);
|
||||
recover(input,re);
|
||||
retval.tree = (Object)adaptor.errorNode(input, retval.start, input.LT(-1), re);
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
// $ANTLR end "parse"
|
||||
|
||||
|
||||
public static class block_return extends ParserRuleReturnScope {
|
||||
Object tree;
|
||||
@Override
|
||||
public Object getTree() { return tree; }
|
||||
};
|
||||
|
||||
|
||||
// $ANTLR start "block"
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:52:1: block : Indent block_atoms Dedent -> ^( BLOCK block_atoms ) ;
|
||||
public final block_return block() throws RecognitionException {
|
||||
block_return retval = new block_return();
|
||||
retval.start = input.LT(1);
|
||||
|
||||
Object root_0 = null;
|
||||
|
||||
Token Indent3=null;
|
||||
Token Dedent5=null;
|
||||
ParserRuleReturnScope block_atoms4 =null;
|
||||
|
||||
Object Indent3_tree=null;
|
||||
Object Dedent5_tree=null;
|
||||
RewriteRuleTokenStream stream_Indent=new RewriteRuleTokenStream(adaptor,"token Indent");
|
||||
RewriteRuleTokenStream stream_Dedent=new RewriteRuleTokenStream(adaptor,"token Dedent");
|
||||
RewriteRuleSubtreeStream stream_block_atoms=new RewriteRuleSubtreeStream(adaptor,"rule block_atoms");
|
||||
|
||||
try {
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:53:2: ( Indent block_atoms Dedent -> ^( BLOCK block_atoms ) )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:53:4: Indent block_atoms Dedent
|
||||
{
|
||||
Indent3=(Token)match(input,Indent,FOLLOW_Indent_in_block91);
|
||||
stream_Indent.add(Indent3);
|
||||
|
||||
pushFollow(FOLLOW_block_atoms_in_block93);
|
||||
block_atoms4=block_atoms();
|
||||
state._fsp--;
|
||||
|
||||
stream_block_atoms.add(block_atoms4.getTree());
|
||||
Dedent5=(Token)match(input,Dedent,FOLLOW_Dedent_in_block95);
|
||||
stream_Dedent.add(Dedent5);
|
||||
|
||||
// AST REWRITE
|
||||
// elements: block_atoms
|
||||
// token labels:
|
||||
// rule labels: retval
|
||||
// token list labels:
|
||||
// rule list labels:
|
||||
// wildcard labels:
|
||||
retval.tree = root_0;
|
||||
RewriteRuleSubtreeStream stream_retval=new RewriteRuleSubtreeStream(adaptor,"rule retval",retval!=null?retval.getTree():null);
|
||||
|
||||
root_0 = (Object)adaptor.nil();
|
||||
// 53:30: -> ^( BLOCK block_atoms )
|
||||
{
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:53:33: ^( BLOCK block_atoms )
|
||||
{
|
||||
Object root_1 = (Object)adaptor.nil();
|
||||
root_1 = (Object)adaptor.becomeRoot((Object)adaptor.create(BLOCK, "BLOCK"), root_1);
|
||||
adaptor.addChild(root_1, stream_block_atoms.nextTree());
|
||||
adaptor.addChild(root_0, root_1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
retval.tree = root_0;
|
||||
|
||||
}
|
||||
|
||||
retval.stop = input.LT(-1);
|
||||
|
||||
retval.tree = (Object)adaptor.rulePostProcessing(root_0);
|
||||
adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop);
|
||||
|
||||
}
|
||||
catch (RecognitionException re) {
|
||||
reportError(re);
|
||||
recover(input,re);
|
||||
retval.tree = (Object)adaptor.errorNode(input, retval.start, input.LT(-1), re);
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
// $ANTLR end "block"
|
||||
|
||||
|
||||
public static class block_atoms_return extends ParserRuleReturnScope {
|
||||
Object tree;
|
||||
@Override
|
||||
public Object getTree() { return tree; }
|
||||
};
|
||||
|
||||
|
||||
// $ANTLR start "block_atoms"
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:56:1: block_atoms : ( Id | block )+ ;
|
||||
public final block_atoms_return block_atoms() throws RecognitionException {
|
||||
block_atoms_return retval = new block_atoms_return();
|
||||
retval.start = input.LT(1);
|
||||
|
||||
Object root_0 = null;
|
||||
|
||||
Token Id6=null;
|
||||
ParserRuleReturnScope block7 =null;
|
||||
|
||||
Object Id6_tree=null;
|
||||
|
||||
try {
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:57:2: ( ( Id | block )+ )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:57:5: ( Id | block )+
|
||||
{
|
||||
root_0 = (Object)adaptor.nil();
|
||||
|
||||
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:57:5: ( Id | block )+
|
||||
int cnt1=0;
|
||||
loop1:
|
||||
while (true) {
|
||||
int alt1=3;
|
||||
int LA1_0 = input.LA(1);
|
||||
if ( (LA1_0==Id) ) {
|
||||
alt1=1;
|
||||
}
|
||||
else if ( (LA1_0==Indent) ) {
|
||||
alt1=2;
|
||||
}
|
||||
|
||||
switch (alt1) {
|
||||
case 1 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:57:6: Id
|
||||
{
|
||||
Id6=(Token)match(input,Id,FOLLOW_Id_in_block_atoms116);
|
||||
Id6_tree = (Object)adaptor.create(Id6);
|
||||
adaptor.addChild(root_0, Id6_tree);
|
||||
|
||||
}
|
||||
break;
|
||||
case 2 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:57:11: block
|
||||
{
|
||||
pushFollow(FOLLOW_block_in_block_atoms120);
|
||||
block7=block();
|
||||
state._fsp--;
|
||||
|
||||
adaptor.addChild(root_0, block7.getTree());
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
if ( cnt1 >= 1 ) break loop1;
|
||||
EarlyExitException eee = new EarlyExitException(1, input);
|
||||
throw eee;
|
||||
}
|
||||
cnt1++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
retval.stop = input.LT(-1);
|
||||
|
||||
retval.tree = (Object)adaptor.rulePostProcessing(root_0);
|
||||
adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop);
|
||||
|
||||
}
|
||||
catch (RecognitionException re) {
|
||||
reportError(re);
|
||||
recover(input,re);
|
||||
retval.tree = (Object)adaptor.errorNode(input, retval.start, input.LT(-1), re);
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
// $ANTLR end "block_atoms"
|
||||
|
||||
|
||||
public static class expression_return extends ParserRuleReturnScope {
|
||||
Object tree;
|
||||
@Override
|
||||
public Object getTree() { return tree; }
|
||||
};
|
||||
|
||||
|
||||
// $ANTLR start "expression"
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:98:1: expression : ( INTEGER )* ;
|
||||
public final expression_return expression() throws RecognitionException {
|
||||
expression_return retval = new expression_return();
|
||||
retval.start = input.LT(1);
|
||||
|
||||
Object root_0 = null;
|
||||
|
||||
Token INTEGER8=null;
|
||||
|
||||
Object INTEGER8_tree=null;
|
||||
|
||||
try {
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:99:2: ( ( INTEGER )* )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:99:4: ( INTEGER )*
|
||||
{
|
||||
root_0 = (Object)adaptor.nil();
|
||||
|
||||
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:99:4: ( INTEGER )*
|
||||
loop2:
|
||||
while (true) {
|
||||
int alt2=2;
|
||||
int LA2_0 = input.LA(1);
|
||||
if ( (LA2_0==INTEGER) ) {
|
||||
alt2=1;
|
||||
}
|
||||
|
||||
switch (alt2) {
|
||||
case 1 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\antlr\\PyEsque.g:99:4: INTEGER
|
||||
{
|
||||
INTEGER8=(Token)match(input,INTEGER,FOLLOW_INTEGER_in_expression246);
|
||||
INTEGER8_tree = (Object)adaptor.create(INTEGER8);
|
||||
adaptor.addChild(root_0, INTEGER8_tree);
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
break loop2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
retval.stop = input.LT(-1);
|
||||
|
||||
retval.tree = (Object)adaptor.rulePostProcessing(root_0);
|
||||
adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop);
|
||||
|
||||
}
|
||||
catch (RecognitionException re) {
|
||||
reportError(re);
|
||||
recover(input,re);
|
||||
retval.tree = (Object)adaptor.errorNode(input, retval.start, input.LT(-1), re);
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
// $ANTLR end "expression"
|
||||
|
||||
// Delegated rules
|
||||
|
||||
|
||||
|
||||
public static final BitSet FOLLOW_block_in_parse74 = new BitSet(new long[]{0x0000000000000000L});
|
||||
public static final BitSet FOLLOW_EOF_in_parse76 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_Indent_in_block91 = new BitSet(new long[]{0x0000000000000300L});
|
||||
public static final BitSet FOLLOW_block_atoms_in_block93 = new BitSet(new long[]{0x0000000000000040L});
|
||||
public static final BitSet FOLLOW_Dedent_in_block95 = new BitSet(new long[]{0x0000000000000002L});
|
||||
public static final BitSet FOLLOW_Id_in_block_atoms116 = new BitSet(new long[]{0x0000000000000302L});
|
||||
public static final BitSet FOLLOW_block_in_block_atoms120 = new BitSet(new long[]{0x0000000000000302L});
|
||||
public static final BitSet FOLLOW_INTEGER_in_expression246 = new BitSet(new long[]{0x0000000000000082L});
|
||||
}
|
|
@ -0,0 +1,611 @@
|
|||
/*
|
||||
[The 'BSD licence']
|
||||
Copyright (c) 2004 Terence Parr and Loring Craymer
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** Python 2.3.3 Grammar
|
||||
*
|
||||
* Terence Parr and Loring Craymer
|
||||
* February 2004
|
||||
*
|
||||
* Converted to ANTLR v3 November 2005 by Terence Parr.
|
||||
*
|
||||
* This grammar was derived automatically from the Python 2.3.3
|
||||
* parser grammar to get a syntactically correct ANTLR grammar
|
||||
* for Python. Then Terence hand tweaked it to be semantically
|
||||
* correct; i.e., removed lookahead issues etc... It is LL(1)
|
||||
* except for the (sometimes optional) trailing commas and semi-colons.
|
||||
* It needs two symbols of lookahead in this case.
|
||||
*
|
||||
* Starting with Loring's preliminary lexer for Python, I modified it
|
||||
* to do my version of the whole nasty INDENT/DEDENT issue just so I
|
||||
* could understand the problem better. This grammar requires
|
||||
* PythonTokenStream.java to work. Also I used some rules from the
|
||||
* semi-formal grammar on the web for Python (automatically
|
||||
* translated to ANTLR format by an ANTLR grammar, naturally <grin>).
|
||||
* The lexical rules for python are particularly nasty and it took me
|
||||
* a long time to get it 'right'; i.e., think about it in the proper
|
||||
* way. Resist changing the lexer unless you've used ANTLR a lot. ;)
|
||||
*
|
||||
* I (Terence) tested this by running it on the jython-2.1/Lib
|
||||
* directory of 40k lines of Python.
|
||||
*
|
||||
* REQUIRES ANTLR v3
|
||||
*/
|
||||
grammar Python;
|
||||
|
||||
|
||||
tokens {
|
||||
INDENT;
|
||||
DEDENT;
|
||||
}
|
||||
|
||||
@lexer::members {
|
||||
/** Handles context-sensitive lexing of implicit line joining such as
|
||||
* the case where newline is ignored in cases like this:
|
||||
* a = [3,
|
||||
* 4]
|
||||
*/
|
||||
int implicitLineJoiningLevel = 0;
|
||||
int startPos=-1;
|
||||
}
|
||||
|
||||
@header {
|
||||
package org.ethereum.serpent;
|
||||
}
|
||||
|
||||
@lexer::header {
|
||||
package org.ethereum.serpent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
single_input
|
||||
: NEWLINE
|
||||
| simple_stmt
|
||||
| compound_stmt NEWLINE
|
||||
;
|
||||
|
||||
file_input
|
||||
: (NEWLINE | stmt)*
|
||||
;
|
||||
|
||||
eval_input
|
||||
: (NEWLINE)* testlist (NEWLINE)*
|
||||
;
|
||||
|
||||
funcdef
|
||||
: 'def' NAME parameters COLON suite
|
||||
{System.out.println("found method def "+$NAME.text);}
|
||||
;
|
||||
|
||||
parameters
|
||||
: LPAREN (varargslist)? RPAREN
|
||||
;
|
||||
|
||||
varargslist
|
||||
: defparameter (options {greedy=true;}:COMMA defparameter)*
|
||||
(COMMA
|
||||
( STAR NAME (COMMA DOUBLESTAR NAME)?
|
||||
| DOUBLESTAR NAME
|
||||
)?
|
||||
)?
|
||||
| STAR NAME (COMMA DOUBLESTAR NAME)?
|
||||
| DOUBLESTAR NAME
|
||||
;
|
||||
|
||||
defparameter
|
||||
: fpdef (ASSIGN test)?
|
||||
;
|
||||
|
||||
fpdef
|
||||
: NAME
|
||||
| LPAREN fplist RPAREN
|
||||
;
|
||||
|
||||
fplist
|
||||
: fpdef (options {greedy=true;}:COMMA fpdef)* (COMMA)?
|
||||
;
|
||||
|
||||
|
||||
stmt: simple_stmt
|
||||
| compound_stmt
|
||||
;
|
||||
|
||||
simple_stmt
|
||||
: small_stmt (options {greedy=true;}:SEMI small_stmt)* (SEMI)? NEWLINE
|
||||
;
|
||||
|
||||
small_stmt: expr_stmt
|
||||
| print_stmt
|
||||
| del_stmt
|
||||
| pass_stmt
|
||||
| flow_stmt
|
||||
| import_stmt
|
||||
| global_stmt
|
||||
| exec_stmt
|
||||
| assert_stmt
|
||||
;
|
||||
|
||||
expr_stmt
|
||||
: testlist
|
||||
( augassign testlist
|
||||
| (ASSIGN testlist)+
|
||||
)?
|
||||
;
|
||||
|
||||
augassign
|
||||
: PLUSEQUAL
|
||||
| MINUSEQUAL
|
||||
| STAREQUAL
|
||||
| SLASHEQUAL
|
||||
| PERCENTEQUAL
|
||||
| AMPEREQUAL
|
||||
| VBAREQUAL
|
||||
| CIRCUMFLEXEQUAL
|
||||
| LEFTSHIFTEQUAL
|
||||
| RIGHTSHIFTEQUAL
|
||||
| DOUBLESTAREQUAL
|
||||
| DOUBLESLASHEQUAL
|
||||
;
|
||||
|
||||
print_stmt:
|
||||
'print'
|
||||
( testlist
|
||||
| RIGHTSHIFT testlist
|
||||
)?
|
||||
;
|
||||
|
||||
del_stmt: 'del' exprlist
|
||||
;
|
||||
|
||||
pass_stmt: 'pass'
|
||||
;
|
||||
|
||||
flow_stmt: break_stmt
|
||||
| continue_stmt
|
||||
| return_stmt
|
||||
| raise_stmt
|
||||
| yield_stmt
|
||||
;
|
||||
|
||||
break_stmt: 'break'
|
||||
;
|
||||
|
||||
continue_stmt: 'continue'
|
||||
;
|
||||
|
||||
return_stmt: 'return' (testlist)?
|
||||
;
|
||||
|
||||
yield_stmt: 'yield' testlist
|
||||
;
|
||||
|
||||
raise_stmt: 'raise' (test (COMMA test (COMMA test)?)?)?
|
||||
;
|
||||
|
||||
import_stmt
|
||||
: 'import' dotted_as_name (COMMA dotted_as_name)*
|
||||
| 'from' dotted_name 'import'
|
||||
(STAR | import_as_name (COMMA import_as_name)*)
|
||||
;
|
||||
|
||||
import_as_name
|
||||
: NAME (NAME NAME)?
|
||||
;
|
||||
|
||||
dotted_as_name: dotted_name (NAME NAME)?
|
||||
;
|
||||
|
||||
dotted_name: NAME (DOT NAME)*
|
||||
;
|
||||
|
||||
global_stmt: 'global' NAME (COMMA NAME)*
|
||||
;
|
||||
|
||||
exec_stmt: 'exec' expr ('in' test (COMMA test)?)?
|
||||
;
|
||||
|
||||
assert_stmt: 'assert' test (COMMA test)?
|
||||
;
|
||||
|
||||
|
||||
compound_stmt: if_stmt
|
||||
| while_stmt
|
||||
| for_stmt
|
||||
| try_stmt
|
||||
| funcdef
|
||||
| classdef
|
||||
;
|
||||
|
||||
if_stmt: 'if' test COLON suite ('elif' test COLON suite)* ('else' COLON suite)?
|
||||
;
|
||||
|
||||
while_stmt: 'while' test COLON suite ('else' COLON suite)?
|
||||
;
|
||||
|
||||
for_stmt: 'for' exprlist 'in' testlist COLON suite ('else' COLON suite)?
|
||||
;
|
||||
|
||||
try_stmt
|
||||
: 'try' COLON suite
|
||||
( (except_clause COLON suite)+ ('else' COLON suite)?
|
||||
| 'finally' COLON suite
|
||||
)
|
||||
;
|
||||
|
||||
except_clause: 'except' (test (COMMA test)?)?
|
||||
;
|
||||
|
||||
suite: simple_stmt
|
||||
| NEWLINE INDENT (stmt)+ DEDENT
|
||||
;
|
||||
|
||||
|
||||
test: and_test ('or' and_test)*
|
||||
| lambdef
|
||||
;
|
||||
|
||||
and_test
|
||||
: not_test ('and' not_test)*
|
||||
;
|
||||
|
||||
not_test
|
||||
: 'not' not_test
|
||||
| comparison
|
||||
;
|
||||
|
||||
comparison: expr (comp_op expr)*
|
||||
;
|
||||
|
||||
comp_op: LESS
|
||||
|GREATER
|
||||
|EQUAL
|
||||
|GREATEREQUAL
|
||||
|LESSEQUAL
|
||||
|ALT_NOTEQUAL
|
||||
|NOTEQUAL
|
||||
|'in'
|
||||
|'not' 'in'
|
||||
|'is'
|
||||
|'is' 'not'
|
||||
;
|
||||
|
||||
expr: xor_expr (VBAR xor_expr)*
|
||||
;
|
||||
|
||||
xor_expr: and_expr (CIRCUMFLEX and_expr)*
|
||||
;
|
||||
|
||||
and_expr: shift_expr (AMPER shift_expr)*
|
||||
;
|
||||
|
||||
shift_expr: arith_expr ((LEFTSHIFT|RIGHTSHIFT) arith_expr)*
|
||||
;
|
||||
|
||||
arith_expr: term ((PLUS|MINUS) term)*
|
||||
;
|
||||
|
||||
term: factor ((STAR | SLASH | PERCENT | DOUBLESLASH ) factor)*
|
||||
;
|
||||
|
||||
factor
|
||||
: (PLUS|MINUS|TILDE) factor
|
||||
| power
|
||||
;
|
||||
|
||||
power
|
||||
: atom (trailer)* (options {greedy=true;}:DOUBLESTAR factor)?
|
||||
;
|
||||
|
||||
atom: LPAREN (testlist)? RPAREN
|
||||
| LBRACK (listmaker)? RBRACK
|
||||
| LCURLY (dictmaker)? RCURLY
|
||||
| BACKQUOTE testlist BACKQUOTE
|
||||
| NAME
|
||||
| INT
|
||||
| LONGINT
|
||||
| FLOAT
|
||||
| COMPLEX
|
||||
| (STRING)+
|
||||
;
|
||||
|
||||
listmaker: test ( list_for | (options {greedy=true;}:COMMA test)* ) (COMMA)?
|
||||
;
|
||||
|
||||
lambdef: 'lambda' (varargslist)? COLON test
|
||||
;
|
||||
|
||||
trailer: LPAREN (arglist)? RPAREN
|
||||
| LBRACK subscriptlist RBRACK
|
||||
| DOT NAME
|
||||
;
|
||||
|
||||
subscriptlist
|
||||
: subscript (options {greedy=true;}:COMMA subscript)* (COMMA)?
|
||||
;
|
||||
|
||||
subscript
|
||||
: DOT DOT DOT
|
||||
| test (COLON (test)? (sliceop)?)?
|
||||
| COLON (test)? (sliceop)?
|
||||
;
|
||||
|
||||
sliceop: COLON (test)?
|
||||
;
|
||||
|
||||
exprlist
|
||||
: expr (options {k=2;}:COMMA expr)* (COMMA)?
|
||||
;
|
||||
|
||||
testlist
|
||||
: test (options {k=2;}: COMMA test)* (COMMA)?
|
||||
;
|
||||
|
||||
dictmaker
|
||||
: test COLON test
|
||||
(options {k=2;}:COMMA test COLON test)* (COMMA)?
|
||||
;
|
||||
|
||||
classdef: 'class' NAME (LPAREN testlist RPAREN)? COLON suite
|
||||
{System.out.println("found class def "+$NAME.text);}
|
||||
;
|
||||
|
||||
arglist: argument (COMMA argument)*
|
||||
( COMMA
|
||||
( STAR test (COMMA DOUBLESTAR test)?
|
||||
| DOUBLESTAR test
|
||||
)?
|
||||
)?
|
||||
| STAR test (COMMA DOUBLESTAR test)?
|
||||
| DOUBLESTAR test
|
||||
;
|
||||
|
||||
argument : test (ASSIGN test)?
|
||||
;
|
||||
|
||||
list_iter: list_for
|
||||
| list_if
|
||||
;
|
||||
|
||||
list_for: 'for' exprlist 'in' testlist (list_iter)?
|
||||
;
|
||||
|
||||
list_if: 'if' test (list_iter)?
|
||||
;
|
||||
|
||||
LPAREN : '(' {implicitLineJoiningLevel++;} ;
|
||||
|
||||
RPAREN : ')' {implicitLineJoiningLevel--;} ;
|
||||
|
||||
LBRACK : '[' {implicitLineJoiningLevel++;} ;
|
||||
|
||||
RBRACK : ']' {implicitLineJoiningLevel--;} ;
|
||||
|
||||
COLON : ':' ;
|
||||
|
||||
COMMA : ',' ;
|
||||
|
||||
SEMI : ';' ;
|
||||
|
||||
PLUS : '+' ;
|
||||
|
||||
MINUS : '-' ;
|
||||
|
||||
STAR : '*' ;
|
||||
|
||||
SLASH : '/' ;
|
||||
|
||||
VBAR : '|' ;
|
||||
|
||||
AMPER : '&' ;
|
||||
|
||||
LESS : '<' ;
|
||||
|
||||
GREATER : '>' ;
|
||||
|
||||
ASSIGN : '=' ;
|
||||
|
||||
PERCENT : '%' ;
|
||||
|
||||
BACKQUOTE : '`' ;
|
||||
|
||||
LCURLY : '{' {implicitLineJoiningLevel++;} ;
|
||||
|
||||
RCURLY : '}' {implicitLineJoiningLevel--;} ;
|
||||
|
||||
CIRCUMFLEX : '^' ;
|
||||
|
||||
TILDE : '~' ;
|
||||
|
||||
EQUAL : '==' ;
|
||||
|
||||
NOTEQUAL : '!=' ;
|
||||
|
||||
ALT_NOTEQUAL: '<>' ;
|
||||
|
||||
LESSEQUAL : '<=' ;
|
||||
|
||||
LEFTSHIFT : '<<' ;
|
||||
|
||||
GREATEREQUAL : '>=' ;
|
||||
|
||||
RIGHTSHIFT : '>>' ;
|
||||
|
||||
PLUSEQUAL : '+=' ;
|
||||
|
||||
MINUSEQUAL : '-=' ;
|
||||
|
||||
DOUBLESTAR : '**' ;
|
||||
|
||||
STAREQUAL : '*=' ;
|
||||
|
||||
DOUBLESLASH : '//' ;
|
||||
|
||||
SLASHEQUAL : '/=' ;
|
||||
|
||||
VBAREQUAL : '|=' ;
|
||||
|
||||
PERCENTEQUAL : '%=' ;
|
||||
|
||||
AMPEREQUAL : '&=' ;
|
||||
|
||||
CIRCUMFLEXEQUAL : '^=' ;
|
||||
|
||||
LEFTSHIFTEQUAL : '<<=' ;
|
||||
|
||||
RIGHTSHIFTEQUAL : '>>=' ;
|
||||
|
||||
DOUBLESTAREQUAL : '**=' ;
|
||||
|
||||
DOUBLESLASHEQUAL : '//=' ;
|
||||
|
||||
DOT : '.' ;
|
||||
|
||||
FLOAT
|
||||
: '.' DIGITS (Exponent)?
|
||||
| DIGITS ('.' (DIGITS (Exponent)?)? | Exponent)
|
||||
;
|
||||
|
||||
LONGINT
|
||||
: INT ('l'|'L')
|
||||
;
|
||||
|
||||
fragment
|
||||
Exponent
|
||||
: ('e' | 'E') ( '+' | '-' )? DIGITS
|
||||
;
|
||||
|
||||
INT : // Hex
|
||||
'0' ('x' | 'X') ( '0' .. '9' | 'a' .. 'f' | 'A' .. 'F' )+
|
||||
('l' | 'L')?
|
||||
| // Octal
|
||||
'0' DIGITS*
|
||||
| '1'..'9' DIGITS*
|
||||
;
|
||||
|
||||
COMPLEX
|
||||
: INT ('j'|'J')
|
||||
| FLOAT ('j'|'J')
|
||||
;
|
||||
|
||||
fragment
|
||||
DIGITS : ( '0' .. '9' )+ ;
|
||||
|
||||
NAME: ( 'a' .. 'z' | 'A' .. 'Z' | '_')
|
||||
( 'a' .. 'z' | 'A' .. 'Z' | '_' | '0' .. '9' )*
|
||||
;
|
||||
|
||||
/** Match various string types. Note that greedy=false implies '''
|
||||
* should make us exit loop not continue.
|
||||
*/
|
||||
STRING
|
||||
: ('r'|'u'|'ur')?
|
||||
( '\'\'\'' (options {greedy=false;}:.)* '\'\'\''
|
||||
| '"""' (options {greedy=false;}:.)* '"""'
|
||||
| '"' (ESC|~('\\'|'\n'|'"'))* '"'
|
||||
| '\'' (ESC|~('\\'|'\n'|'\''))* '\''
|
||||
)
|
||||
;
|
||||
|
||||
fragment
|
||||
ESC
|
||||
: '\\' .
|
||||
;
|
||||
|
||||
/** Consume a newline and any whitespace at start of next line */
|
||||
CONTINUED_LINE
|
||||
: '\\' ('\r')? '\n' (' '|'\t')* { $channel=HIDDEN; }
|
||||
;
|
||||
|
||||
/** Treat a sequence of blank lines as a single blank line. If
|
||||
* nested within a (..), {..}, or [..], then ignore newlines.
|
||||
* If the first newline starts in column one, they are to be ignored.
|
||||
*/
|
||||
NEWLINE
|
||||
: (('\r')? '\n' )+
|
||||
{if ( startPos==0 || implicitLineJoiningLevel>0 )
|
||||
$channel=HIDDEN;
|
||||
}
|
||||
;
|
||||
|
||||
WS : {startPos>0}?=> (' '|'\t')+ {$channel=HIDDEN;}
|
||||
;
|
||||
|
||||
/** Grab everything before a real symbol. Then if newline, kill it
|
||||
* as this is a blank line. If whitespace followed by comment, kill it
|
||||
* as it's a comment on a line by itself.
|
||||
*
|
||||
* Ignore leading whitespace when nested in [..], (..), {..}.
|
||||
*/
|
||||
LEADING_WS
|
||||
@init {
|
||||
int spaces = 0;
|
||||
}
|
||||
: {startPos==0}?=>
|
||||
( {implicitLineJoiningLevel>0}? ( ' ' | '\t' )+ {$channel=HIDDEN;}
|
||||
| ( ' ' { spaces++; }
|
||||
| '\t' { spaces += 8; spaces -= (spaces \% 8); }
|
||||
)+
|
||||
{
|
||||
// make a string of n spaces where n is column number - 1
|
||||
char[] indentation = new char[spaces];
|
||||
for (int i=0; i<spaces; i++) {
|
||||
indentation[i] = ' ';
|
||||
}
|
||||
String s = new String(indentation);
|
||||
emit(new ClassicToken(LEADING_WS,new String(indentation)));
|
||||
}
|
||||
// kill trailing newline if present and then ignore
|
||||
( ('\r')? '\n' {if (state.token!=null) state.token.setChannel(HIDDEN); else $channel=HIDDEN;})*
|
||||
// {token.setChannel(99); }
|
||||
)
|
||||
;
|
||||
|
||||
/** Comments not on line by themselves are turned into newlines.
|
||||
|
||||
b = a # end of line comment
|
||||
|
||||
or
|
||||
|
||||
a = [1, # weird
|
||||
2]
|
||||
|
||||
This rule is invoked directly by nextToken when the comment is in
|
||||
first column or when comment is on end of nonwhitespace line.
|
||||
|
||||
Only match \n here if we didn't start on left edge; let NEWLINE return that.
|
||||
Kill if newlines if we live on a line by ourselves
|
||||
|
||||
Consume any leading whitespace if it starts on left edge.
|
||||
*/
|
||||
COMMENT
|
||||
@init {
|
||||
$channel=HIDDEN;
|
||||
}
|
||||
: {startPos==0}?=> (' '|'\t')* '#' (~'\n')* '\n'+
|
||||
| {startPos>0}?=> '#' (~'\n')* // let NEWLINE handle \n unless char pos==0 for '#'
|
||||
;
|
|
@ -0,0 +1,201 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Scott Stanchfield
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
grammar Sample;
|
||||
|
||||
options {
|
||||
language = Java;
|
||||
output = AST;
|
||||
output=template;
|
||||
}
|
||||
|
||||
@header {
|
||||
package samples.antlr;
|
||||
}
|
||||
|
||||
@lexer::header {
|
||||
package samples.antlr;
|
||||
}
|
||||
|
||||
program
|
||||
: 'program' IDENT '='
|
||||
(constant | variable | function | procedure | typeDecl)*
|
||||
'begin'
|
||||
statement*
|
||||
'end' IDENT '.'
|
||||
;
|
||||
|
||||
constant
|
||||
: 'constant' IDENT ':' type ':=' expression ';'
|
||||
;
|
||||
|
||||
variable
|
||||
: 'var' IDENT (',' IDENT)* ':' type (':=' expression)? ';'
|
||||
;
|
||||
|
||||
type
|
||||
: 'Integer'
|
||||
| 'Boolean'
|
||||
| 'String'
|
||||
| 'Char'
|
||||
| IDENT
|
||||
| typeSpec
|
||||
;
|
||||
|
||||
typeDecl
|
||||
: 'type' IDENT '=' typeSpec ';'
|
||||
;
|
||||
|
||||
typeSpec
|
||||
: arrayType
|
||||
| recordType
|
||||
| enumType
|
||||
;
|
||||
|
||||
arrayType
|
||||
: 'array' '[' INTEGER '..' INTEGER ']' 'of' type
|
||||
;
|
||||
|
||||
recordType
|
||||
: 'record' field* 'end' 'record'
|
||||
;
|
||||
|
||||
field
|
||||
: IDENT ':' type ';'
|
||||
;
|
||||
|
||||
enumType
|
||||
: '<' IDENT (',' IDENT)* '>'
|
||||
;
|
||||
|
||||
statement
|
||||
: assignmentStatement
|
||||
| ifStatement
|
||||
| loopStatement
|
||||
| whileStatement
|
||||
| procedureCallStatement
|
||||
;
|
||||
|
||||
procedureCallStatement
|
||||
: IDENT '(' actualParameters? ')' ';'
|
||||
;
|
||||
|
||||
actualParameters
|
||||
: expression (',' expression)*
|
||||
;
|
||||
|
||||
ifStatement
|
||||
: 'if' expression 'then' statement+
|
||||
('elsif' expression 'then' statement+)*
|
||||
('else' statement+)?
|
||||
'end' 'if' ';'
|
||||
;
|
||||
|
||||
assignmentStatement
|
||||
: IDENT ':=' expression ';'
|
||||
;
|
||||
|
||||
exitStatement
|
||||
: 'exit' 'when' expression ';'
|
||||
;
|
||||
|
||||
whileStatement
|
||||
: 'while' expression 'loop'
|
||||
(statement|exitStatement)*
|
||||
'end' 'loop' ';'
|
||||
;
|
||||
|
||||
loopStatement
|
||||
: 'loop' (statement|exitStatement)* 'end' 'loop' ';'
|
||||
;
|
||||
|
||||
returnStatement
|
||||
: 'return' expression ';'
|
||||
;
|
||||
|
||||
procedure
|
||||
: 'procedure' IDENT '(' parameters? ')' '='
|
||||
(constant | variable)*
|
||||
'begin'
|
||||
statement*
|
||||
'end' IDENT '.'
|
||||
;
|
||||
function
|
||||
: 'function' IDENT '(' parameters? ')' ':' type '='
|
||||
(constant | variable)*
|
||||
'begin'
|
||||
(statement|returnStatement)*
|
||||
'end' IDENT '.'
|
||||
;
|
||||
|
||||
parameters
|
||||
: parameter (',' parameter)*
|
||||
;
|
||||
|
||||
parameter
|
||||
: 'var'? IDENT ':' type
|
||||
;
|
||||
|
||||
|
||||
// expressions -- fun time!
|
||||
|
||||
term
|
||||
: IDENT
|
||||
| '(' expression ')'
|
||||
| INTEGER
|
||||
| STRING_LITERAL
|
||||
| CHAR_LITERAL
|
||||
| IDENT '(' actualParameters ')'
|
||||
;
|
||||
|
||||
negation
|
||||
: 'not'* term
|
||||
;
|
||||
|
||||
unary
|
||||
: ('+' | '-')* negation
|
||||
;
|
||||
|
||||
mult
|
||||
: unary (('*' | '/' | 'mod') unary)*
|
||||
;
|
||||
|
||||
add
|
||||
: mult (('+' | '-') mult)*
|
||||
;
|
||||
|
||||
relation
|
||||
: add (('=' | '/=' | '<' | '<=' | '>=' | '>') add)*
|
||||
;
|
||||
|
||||
expression
|
||||
: relation (('and' | 'or') relation)*
|
||||
;
|
||||
|
||||
|
||||
MULTILINE_COMMENT : '/*' .* '*/' {$channel = HIDDEN;} ;
|
||||
|
||||
STRING_LITERAL
|
||||
: '"'
|
||||
{ StringBuilder b = new StringBuilder(); }
|
||||
( '"' '"' { b.appendCodePoint('"');}
|
||||
| c=~('"'|'\r'|'\n') { b.appendCodePoint(c);}
|
||||
)*
|
||||
'"'
|
||||
{ setText(b.toString()); }
|
||||
;
|
||||
|
||||
CHAR_LITERAL
|
||||
: '\'' . '\'' {setText(getText().substring(1,2));}
|
||||
;
|
||||
|
||||
fragment LETTER : ('a'..'z' | 'A'..'Z') ;
|
||||
fragment DIGIT : '0'..'9';
|
||||
INTEGER : DIGIT+ ;
|
||||
IDENT : LETTER (LETTER | DIGIT)*;
|
||||
WS : (' ' | '\t' | '\n' | '\r' | '\f')+ {$channel = HIDDEN;};
|
||||
COMMENT : '//' .* ('\n'|'\r') {$channel = HIDDEN;};
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
/** https://github.com/rollxx/antlr-php-runtime/blob/master/examples/cminus/Bytecode.stg */
|
||||
|
||||
|
||||
|
||||
variable(type,name) ::= ".var is <name> <type><\n>"
|
||||
|
||||
type_int() ::= "I"
|
||||
|
||||
type_char() ::= "C"
|
|
@ -0,0 +1,81 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Scott Stanchfield
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package samples.antlr;
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
import org.antlr.runtime.tree.CommonTree;
|
||||
import org.antlr.runtime.tree.DOTTreeGenerator;
|
||||
import org.antlr.stringtemplate.StringTemplate;
|
||||
import org.antlr.stringtemplate.StringTemplateGroup;
|
||||
|
||||
|
||||
|
||||
public class Test1 {
|
||||
public static void main(String[] args) throws RecognitionException {
|
||||
CharStream stream =
|
||||
new ANTLRStringStream("program XLSample1 =\r\n" +
|
||||
"/*\r\n" +
|
||||
" constant one : Integer := 1;\r\n" +
|
||||
" constant two : Integer := 2 * 3;\r\n" +
|
||||
" var x, y, z : Integer := 42;\r\n" +
|
||||
"*/\r\n" +
|
||||
"\r\n" +
|
||||
" procedure foo() =\r\n" +
|
||||
" var x : Integer := 2;\r\n" +
|
||||
" begin\r\n" +
|
||||
" end foo.\r\n" +
|
||||
" procedure fee(y : Integer) =\r\n" +
|
||||
" var x : Integer := 2;\r\n" +
|
||||
" begin\r\n" +
|
||||
" end fee.\r\n" +
|
||||
" function fie(y : Integer) : Integer =\r\n" +
|
||||
" var x : Integer := 2;\r\n" +
|
||||
" begin\r\n" +
|
||||
" return y;\r\n" +
|
||||
" end fie.\r\n" +
|
||||
"begin\r\n" +
|
||||
"end XLSample1.");
|
||||
SampleLexer lexer = new SampleLexer(stream);
|
||||
TokenStream tokenStream = new CommonTokenStream(lexer);
|
||||
SampleParser parser = new SampleParser(tokenStream);
|
||||
CommonTree astTree = (CommonTree) parser.program().getTree();
|
||||
|
||||
DOTTreeGenerator gen = new DOTTreeGenerator();
|
||||
StringTemplate st = gen.toDOT(astTree);
|
||||
|
||||
|
||||
String userDir = System.getProperty("user.dir");
|
||||
|
||||
String stgFile = userDir + "\\src\\main\\java\\samples\\antlr\\Sample2Asm.stg";
|
||||
|
||||
|
||||
|
||||
StringTemplateGroup stg = new StringTemplateGroup(stgFile);
|
||||
|
||||
parser.setTemplateLib(stg);
|
||||
|
||||
RuleReturnScope r = parser.program();
|
||||
// System.out.println(r.getTemplate().toString());
|
||||
|
||||
|
||||
|
||||
// System.out.println(st);
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Lexical Analysis (scanning)
|
||||
Semantic Analysis (parsing)
|
||||
Tree Generation ==> Abstract Syntax Tree (AST)
|
||||
Code Generation ==> using stg file
|
||||
Interpretation
|
||||
*/
|
||||
System.out.println("ok");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package samples.netty;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 10/04/14 08:20
|
||||
*/
|
||||
public class Client {
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
String host = "85.65.126.45";
|
||||
int port = 10101;
|
||||
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
|
||||
try {
|
||||
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.group(workerGroup);
|
||||
b.channel(NioSocketChannel.class);
|
||||
|
||||
b.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
b.handler(new ChannelInitializer<NioSocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(NioSocketChannel ch) throws Exception {
|
||||
ch.pipeline().addLast(new ClientMessageHandler());
|
||||
}
|
||||
});
|
||||
|
||||
// Start the client.
|
||||
ChannelFuture f = b.connect(host, port).sync(); // (5)
|
||||
|
||||
// Wait until the connection is closed.
|
||||
f.channel().closeFuture().sync();
|
||||
} finally {
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package samples.netty;
|
||||
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 10/04/14 08:19
|
||||
*/
|
||||
public class ClientMessageHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
|
||||
|
||||
ByteBuf input = ((ByteBuf)msg);
|
||||
|
||||
try {
|
||||
|
||||
int inputSize = input.readableBytes();
|
||||
byte[] payload = new byte[inputSize];
|
||||
input.readBytes(payload);
|
||||
|
||||
if (payload.length < 5){
|
||||
System.out.println("Not a Roman server disconnect");
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
String prefix = new String(payload, 0, 5);
|
||||
|
||||
if (!prefix.equals("9191-")){
|
||||
System.out.println("Not a Roman server disconnect");
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
|
||||
String newMessage = new String(payload);
|
||||
System.out.println(newMessage);
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
String answer = RomanProtocol.getAnswer(newMessage);
|
||||
final ByteBuf buffer = ctx.alloc().buffer(answer.length());
|
||||
buffer.writeBytes(answer.getBytes());
|
||||
ctx.writeAndFlush(buffer);
|
||||
|
||||
// String answer2 = "cool sir 2!!!";
|
||||
// final ByteBuf helloMessage2 = ctx.alloc().buffer(answer2.length());
|
||||
// helloMessage2.writeBytes(answer2.getBytes());
|
||||
// ctx.writeAndFlush(helloMessage2);
|
||||
|
||||
|
||||
} finally {
|
||||
ReferenceCountUtil.release(input);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package samples.netty;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 10/04/14 11:19
|
||||
*/
|
||||
public class RomanProtocol {
|
||||
|
||||
|
||||
public static String getAnswer(String msg){
|
||||
|
||||
if (msg.equals("9191-Hello"))
|
||||
return ("9191-Good day sir");
|
||||
|
||||
if (msg.equals("9191-Good day sir"))
|
||||
return ("9191-What is you name");
|
||||
|
||||
if (msg.equals("9191-What is you name"))
|
||||
return ("9191-My Name is Ethereum");
|
||||
|
||||
if (msg.matches("9191-My Name is ([\\w])*")) {
|
||||
|
||||
String name = msg.substring(16);
|
||||
|
||||
return ("9191-Good to see you: " + name);
|
||||
}
|
||||
|
||||
if (msg.matches("9191-Good to see you: ([\\w])*")) {
|
||||
|
||||
return ("9191-Hello");
|
||||
}
|
||||
|
||||
|
||||
return "9191-Sorry I don't understand you";
|
||||
}
|
||||
|
||||
public static void main(String args[]){
|
||||
|
||||
System.out.println(getAnswer("9191-My Name is Vasia"));
|
||||
|
||||
|
||||
// 1800-0770-77
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package samples.netty;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 10/04/14 08:20
|
||||
*/
|
||||
public class Server {
|
||||
|
||||
int port;
|
||||
|
||||
|
||||
public Server(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
|
||||
public void start(){
|
||||
|
||||
EventLoopGroup bossGroup = new NioEventLoopGroup();
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
|
||||
|
||||
ServerBootstrap bootstrap = new ServerBootstrap();
|
||||
bootstrap.group(bossGroup, workerGroup)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.childHandler(new ChannelInitializer<NioSocketChannel>() {
|
||||
|
||||
public void initChannel(NioSocketChannel channel){
|
||||
|
||||
channel.pipeline().addLast(new ServerMessageHandler());
|
||||
|
||||
};
|
||||
|
||||
}).option(ChannelOption.SO_BACKLOG, 128)
|
||||
.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
|
||||
try {
|
||||
|
||||
System.out.println("Server started");
|
||||
ChannelFuture future = bootstrap.bind(port).sync();
|
||||
|
||||
future.channel().closeFuture().sync();
|
||||
|
||||
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
workerGroup.shutdownGracefully();
|
||||
bossGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]){
|
||||
|
||||
new Server(10101).start();
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package samples.netty;
|
||||
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 10/04/14 08:19
|
||||
*/
|
||||
public class ServerMessageHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
|
||||
@Override
|
||||
public void channelActive(final ChannelHandlerContext ctx) {
|
||||
|
||||
String helloString = "9191-Hello";
|
||||
|
||||
final ByteBuf helloMessage = ctx.alloc().buffer(helloString.length());
|
||||
helloMessage.writeBytes(helloString.getBytes());
|
||||
|
||||
final ChannelFuture channelFuture = ctx.writeAndFlush(helloMessage);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
|
||||
|
||||
ByteBuf input = ((ByteBuf)msg);
|
||||
|
||||
try {
|
||||
|
||||
int inputSize = input.readableBytes();
|
||||
byte[] payload = new byte[inputSize];
|
||||
input.readBytes(payload);
|
||||
|
||||
String newMessage = new String(payload);
|
||||
System.out.println(newMessage);
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
String answer = RomanProtocol.getAnswer(newMessage);
|
||||
final ByteBuf buffer = ctx.alloc().buffer(answer.length());
|
||||
buffer.writeBytes(answer.getBytes());
|
||||
ctx.writeAndFlush(buffer);
|
||||
|
||||
|
||||
|
||||
|
||||
} finally {
|
||||
ReferenceCountUtil.release(input);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
|
||||
System.out.println("Client disconnected");
|
||||
// cause.printStackTrace();
|
||||
ctx.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package samples.niotut;
|
||||
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
public class ChangeRequest {
|
||||
public static final int REGISTER = 1;
|
||||
public static final int CHANGEOPS = 2;
|
||||
|
||||
public SocketChannel socket;
|
||||
public int type;
|
||||
public int ops;
|
||||
|
||||
public ChangeRequest(SocketChannel socket, int type, int ops) {
|
||||
this.socket = socket;
|
||||
this.type = type;
|
||||
this.ops = ops;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package samples.niotut;
|
||||
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class EchoWorker implements Runnable {
|
||||
private List queue = new LinkedList();
|
||||
|
||||
public void processData(NioServer server, SocketChannel socket, byte[] data, int count) {
|
||||
byte[] dataCopy = new byte[count];
|
||||
System.arraycopy(data, 0, dataCopy, 0, count);
|
||||
synchronized(queue) {
|
||||
queue.add(new ServerDataEvent(server, socket, dataCopy));
|
||||
queue.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
ServerDataEvent dataEvent;
|
||||
|
||||
while(true) {
|
||||
// Wait for data to become available
|
||||
synchronized(queue) {
|
||||
while(queue.isEmpty()) {
|
||||
try {
|
||||
queue.wait();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
dataEvent = (ServerDataEvent) queue.remove(0);
|
||||
}
|
||||
|
||||
// Return to sender
|
||||
dataEvent.server.send(dataEvent.socket, dataEvent.data);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,403 @@
|
|||
package samples.niotut;
|
||||
|
||||
|
||||
/* BASED ON: http://rox-xmlrpc.sourceforge.net/niotut/#The client */
|
||||
|
||||
import org.ethereum.util.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.*;
|
||||
|
||||
public class NioClient implements Runnable {
|
||||
// The host:port combination to connect to
|
||||
private InetAddress hostAddress;
|
||||
private int port;
|
||||
|
||||
// The selector we'll be monitoring
|
||||
private Selector selector;
|
||||
|
||||
// The buffer into which we'll read data when it's available
|
||||
private ByteBuffer readBuffer = ByteBuffer.allocate(8192);
|
||||
|
||||
// A list of PendingChange instances
|
||||
private List pendingChanges = new LinkedList();
|
||||
|
||||
// Maps a SocketChannel to a list of ByteBuffer instances
|
||||
private Map pendingData = new HashMap();
|
||||
|
||||
// Maps a SocketChannel to a RspHandler
|
||||
private Map rspHandlers = Collections.synchronizedMap(new HashMap());
|
||||
|
||||
public SocketChannel socket;
|
||||
public RspHandler handler;
|
||||
|
||||
|
||||
public static final String helloString = "22 40 08 91 00 00 00 79 F8 77 80 0B 80 AD 45 74 " +
|
||||
"68 65 72 65 75 6D 28 2B 2B 29 2F 5A 65 72 6F 47 " +
|
||||
"6F 78 2F 76 30 2E 34 2E 31 2F 6E 63 75 72 73 65 " +
|
||||
"73 2F 4C 69 6E 75 78 2F 67 2B 2B 07 82 76 5F B8 " +
|
||||
"40 D8 D6 0C 25 80 FA 79 5C FC 03 13 EF DE BA 86 " +
|
||||
"9D 21 94 E7 9E 7C B2 B5 22 F7 82 FF A0 39 2C BB " +
|
||||
"AB 8D 1B AC 30 12 08 B1 37 E0 DE 49 98 33 4F 3B " +
|
||||
"CF 73 FA 11 7E F2 13 F8 74 17 08 9F EA F8 4C 21 " +
|
||||
"B0 ";
|
||||
|
||||
public static final String pingString = "22 40 08 91 00 00 00 02 C1 02 ";
|
||||
public static final String pongString = "22 40 08 91 00 00 00 02 C1 03 ";
|
||||
|
||||
public static final String getPeersString = "22 40 08 91 00 00 00 02 C1 10 ";
|
||||
|
||||
public static final String getTransactions = "22 40 08 91 00 00 00 02 C1 16 ";
|
||||
|
||||
public static final String getChain = "22 40 08 91 00 00 00 26 F8 24 14 " +
|
||||
"AB 6B 9A 56 13 97 0F AA 77 1B 12 D4 49 B2 E9 BB 92 5A B7 A3 69 F0 A4 B8 6B 28 6E 9D 54 00 99 CF " +
|
||||
"82 01 00 ";
|
||||
|
||||
public static final String getTxString = "22 40 08 91 00 00 00 02 C1 16 ";
|
||||
|
||||
|
||||
|
||||
public NioClient(InetAddress hostAddress, int port) throws IOException {
|
||||
this.hostAddress = hostAddress;
|
||||
this.port = port;
|
||||
this.selector = this.initSelector();
|
||||
|
||||
// Start a new connection
|
||||
this.socket = this.initiateConnection();
|
||||
|
||||
// Register the response handler
|
||||
this.handler = new RspHandler();
|
||||
this.rspHandlers.put(socket, handler);
|
||||
|
||||
}
|
||||
|
||||
public void send(byte[] data) throws IOException {
|
||||
|
||||
// And queue the data we want written
|
||||
synchronized (this.pendingData) {
|
||||
List queue = (List) this.pendingData.get(socket);
|
||||
if (queue == null) {
|
||||
queue = new ArrayList();
|
||||
this.pendingData.put(socket, queue);
|
||||
}
|
||||
queue.add(ByteBuffer.wrap(data));
|
||||
}
|
||||
|
||||
// Finally, wake up our selecting thread so it can make the required changes
|
||||
this.selector.wakeup();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
// Process any pending changes
|
||||
synchronized (this.pendingChanges) {
|
||||
Iterator changes = this.pendingChanges.iterator();
|
||||
while (changes.hasNext()) {
|
||||
ChangeRequest change = (ChangeRequest) changes.next();
|
||||
|
||||
switch (change.type) {
|
||||
case ChangeRequest.CHANGEOPS:
|
||||
SelectionKey key = change.socket.keyFor(this.selector);
|
||||
key.interestOps(change.ops);
|
||||
break;
|
||||
case ChangeRequest.REGISTER:
|
||||
change.socket.register(this.selector, change.ops);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.pendingChanges.clear();
|
||||
}
|
||||
|
||||
// Wait for an event one of the registered channels
|
||||
// THIS ONE ACTUALLY BLOCKS AND SHOULD AWAKE WHEN SOME I/O HAPPENS
|
||||
this.selector.select();
|
||||
|
||||
// Iterate over the set of keys for which events are available
|
||||
Iterator selectedKeys = this.selector.selectedKeys().iterator();
|
||||
while (selectedKeys.hasNext()) {
|
||||
SelectionKey key = (SelectionKey) selectedKeys.next();
|
||||
selectedKeys.remove();
|
||||
|
||||
if (!key.isValid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check what event is available and deal with it
|
||||
if (key.isConnectable()) {
|
||||
this.establishConnection(key);
|
||||
} else if (key.isReadable()) {
|
||||
this.read(key);
|
||||
} else if (key.isWritable()) {
|
||||
this.write(key);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void read(SelectionKey key) throws IOException {
|
||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
||||
|
||||
// Clear out our read buffer so it's ready for new data
|
||||
this.readBuffer.clear();
|
||||
|
||||
// Attempt to read off the channel
|
||||
int numRead;
|
||||
try {
|
||||
|
||||
numRead = socketChannel.read(this.readBuffer);
|
||||
System.out.println("reading: " + numRead);
|
||||
// key.interestOps(SelectionKey.OP_WRITE);
|
||||
|
||||
} catch (IOException e) {
|
||||
// The remote forcibly closed the connection, cancel
|
||||
// the selection key and close the channel.
|
||||
key.cancel();
|
||||
socketChannel.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (numRead == -1) {
|
||||
// Remote entity shut the socket down cleanly. Do the
|
||||
// same from our end and cancel the channel.
|
||||
// key.channel().close();
|
||||
// key.cancel();
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the response
|
||||
|
||||
|
||||
this.handleResponse(socketChannel, this.readBuffer.array(), numRead);
|
||||
}
|
||||
|
||||
private void handleResponse(SocketChannel socketChannel, byte[] data, int numRead) throws IOException {
|
||||
|
||||
// Make a correctly sized copy of the data before handing it
|
||||
// to the client
|
||||
byte[] rspData = new byte[numRead];
|
||||
System.arraycopy(data, 0, rspData, 0, numRead);
|
||||
|
||||
|
||||
|
||||
// Look up the handler for this channel
|
||||
RspHandler handler = (RspHandler) this.rspHandlers.get(socketChannel);
|
||||
|
||||
// And pass the response to it
|
||||
if (handler.handleResponse(rspData)) {
|
||||
// The handler has seen enough, close the connection
|
||||
// socketChannel.close();
|
||||
// socketChannel.keyFor(this.selector).cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void write(SelectionKey key) throws IOException {
|
||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
||||
|
||||
synchronized (this.pendingData) {
|
||||
List queue = (List) this.pendingData.get(socketChannel);
|
||||
|
||||
|
||||
// Write until there's not more data ...
|
||||
while (queue != null && !queue.isEmpty()) {
|
||||
ByteBuffer buf = (ByteBuffer) queue.get(0);
|
||||
byte[] packet = buf.array();
|
||||
|
||||
System.out.print("write: ");
|
||||
Utils.printHexStringForByteArray(packet);
|
||||
|
||||
socketChannel.write(buf);
|
||||
|
||||
if (buf.remaining() > 0) {
|
||||
// ... or the socket's buffer fills up
|
||||
break;
|
||||
}
|
||||
queue.remove(0);
|
||||
}
|
||||
// key.interestOps(SelectionKey.OP_READ);
|
||||
|
||||
if (queue == null || queue.isEmpty()) {
|
||||
// We wrote away all data, so we're no longer interested
|
||||
// in writing on this socket. Switch back to waiting for
|
||||
// data.
|
||||
key.interestOps(SelectionKey.OP_READ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void establishConnection(SelectionKey key) throws IOException {
|
||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
||||
|
||||
// Finish the connection. If the connection operation failed
|
||||
// this will raise an IOException.
|
||||
try {
|
||||
socketChannel.finishConnect();
|
||||
} catch (IOException e) {
|
||||
// Cancel the channel's registration with our selector
|
||||
System.out.println(e);
|
||||
key.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
// Register an interest in writing on this channel
|
||||
key.interestOps(SelectionKey.OP_WRITE);
|
||||
}
|
||||
|
||||
private SocketChannel initiateConnection() throws IOException {
|
||||
// Create a non-blocking socket channel
|
||||
SocketChannel socketChannel = SocketChannel.open();
|
||||
socketChannel.configureBlocking(false);
|
||||
|
||||
// Kick off connection establishment
|
||||
socketChannel.connect(new InetSocketAddress(this.hostAddress, this.port));
|
||||
|
||||
// Queue a channel registration since the caller is not the
|
||||
// selecting thread. As part of the registration we'll register
|
||||
// an interest in connection events. These are raised when a channel
|
||||
// is ready to complete connection establishment.
|
||||
synchronized(this.pendingChanges) {
|
||||
this.pendingChanges.add(new ChangeRequest(socketChannel,
|
||||
ChangeRequest.REGISTER, SelectionKey.OP_CONNECT));
|
||||
}
|
||||
|
||||
return socketChannel;
|
||||
}
|
||||
|
||||
private Selector initSelector() throws IOException {
|
||||
// Create a new selector
|
||||
return SelectorProvider.provider().openSelector();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
|
||||
NioClient client = new NioClient(InetAddress.getByName("localhost"), 20202);
|
||||
Thread t = new Thread(client, "ClientThread");
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
|
||||
// client.send(new byte[0]);
|
||||
// client.handler.waitForResponse();
|
||||
Thread.sleep(2000);
|
||||
|
||||
|
||||
System.out.println("\nsending HELLO");
|
||||
client.enableWriting();
|
||||
// client.send(hexStringToByteArr(helloString));
|
||||
Thread.sleep(100);
|
||||
|
||||
System.out.println("\nsending PONG");
|
||||
// client.enableWriting();
|
||||
// client.send(hexStringToByteArr(pongString));
|
||||
|
||||
Thread.sleep(100);
|
||||
System.out.println("\nsending GETCHAIN");
|
||||
// client.enableWriting();
|
||||
// client.send(hexStringToByteArr(getChain));
|
||||
|
||||
|
||||
|
||||
|
||||
// System.out.println("\nsending PING");
|
||||
// client.send(hexStringToByteArr(pingString));
|
||||
// client.handler.waitForResponse();
|
||||
|
||||
|
||||
System.out.println("SLEEPING");
|
||||
Thread.sleep(5000);
|
||||
|
||||
client.handler.waitForResponse();
|
||||
|
||||
// System.out.println("\nsending GETCHAIN");
|
||||
// client.send(hexStringToByteArr(getChain));
|
||||
// client.handler.waitForResponse();
|
||||
|
||||
|
||||
// System.out.println("\nsending GETPEERS");
|
||||
// client.send(hexStringToByteArr(getPeersString));
|
||||
// client.handler.waitForResponse();
|
||||
// client.handler.waitForResponse();
|
||||
|
||||
// System.out.println("\nsending GETTRANSACTIONS");
|
||||
// client.send(hexStringToByteArr(getTransactions));
|
||||
|
||||
|
||||
System.out.println("\nsleeping 5 secs before death");
|
||||
|
||||
|
||||
Thread.sleep(5000);
|
||||
|
||||
client.socket.close();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
client.send(hexStringToByteArr(helloString));
|
||||
client.handler.waitForResponse();
|
||||
|
||||
|
||||
System.out.println("");
|
||||
client.send(hexStringToByteArr(getPeersString));
|
||||
client.handler.waitForResponse();
|
||||
|
||||
|
||||
System.out.println("");
|
||||
client.handler.waitForResponse();
|
||||
|
||||
System.out.println("");
|
||||
client.handler.waitForResponse();
|
||||
*/
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static byte[] hexStringToByteArr(String hexString){
|
||||
|
||||
String hexSymbols = "0123456789ABCDEF";
|
||||
|
||||
int arrSize = (int) (hexString.length() / 3);
|
||||
byte[] result = new byte[arrSize];
|
||||
|
||||
for (int i = 0; i < arrSize; ++i){
|
||||
|
||||
int digit1 = hexSymbols.indexOf( hexString.charAt(i * 3) );
|
||||
int digit2 = hexSymbols.indexOf( hexString.charAt(i * 3 + 1) );
|
||||
|
||||
result[i] = (byte) (digit1 * 16 + digit2);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public void enableWriting(){
|
||||
SelectionKey key = this.socket.keyFor(this.selector);
|
||||
key.interestOps(SelectionKey.OP_WRITE | SelectionKey.OP_READ);
|
||||
}
|
||||
|
||||
public void enableOnlyReading(){
|
||||
SelectionKey key = this.socket.keyFor(this.selector);
|
||||
key.interestOps(SelectionKey.OP_READ);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,213 @@
|
|||
package samples.niotut;
|
||||
|
||||
|
||||
/* BASED ON: http://rox-xmlrpc.sourceforge.net/niotut/#The client */
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.*;
|
||||
|
||||
public class NioServer implements Runnable {
|
||||
// The host:port combination to listen on
|
||||
private InetAddress hostAddress;
|
||||
private int port;
|
||||
|
||||
// The channel on which we'll accept connections
|
||||
private ServerSocketChannel serverChannel;
|
||||
|
||||
// The selector we'll be monitoring
|
||||
private Selector selector;
|
||||
|
||||
// The buffer into which we'll read data when it's available
|
||||
private ByteBuffer readBuffer = ByteBuffer.allocate(8192);
|
||||
|
||||
private EchoWorker worker;
|
||||
|
||||
// A list of PendingChange instances
|
||||
private List pendingChanges = new LinkedList();
|
||||
|
||||
// Maps a SocketChannel to a list of ByteBuffer instances
|
||||
private Map pendingData = new HashMap();
|
||||
|
||||
public NioServer(InetAddress hostAddress, int port, EchoWorker worker) throws IOException {
|
||||
this.hostAddress = hostAddress;
|
||||
this.port = port;
|
||||
this.selector = this.initSelector();
|
||||
this.worker = worker;
|
||||
}
|
||||
|
||||
public void send(SocketChannel socket, byte[] data) {
|
||||
synchronized (this.pendingChanges) {
|
||||
// Indicate we want the interest ops set changed
|
||||
this.pendingChanges.add(new ChangeRequest(socket, ChangeRequest.CHANGEOPS, SelectionKey.OP_WRITE));
|
||||
|
||||
// And queue the data we want written
|
||||
synchronized (this.pendingData) {
|
||||
List queue = (List) this.pendingData.get(socket);
|
||||
if (queue == null) {
|
||||
queue = new ArrayList();
|
||||
this.pendingData.put(socket, queue);
|
||||
}
|
||||
queue.add(ByteBuffer.wrap(data));
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, wake up our selecting thread so it can make the required changes
|
||||
this.selector.wakeup();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
// Process any pending changes
|
||||
synchronized (this.pendingChanges) {
|
||||
Iterator changes = this.pendingChanges.iterator();
|
||||
while (changes.hasNext()) {
|
||||
ChangeRequest change = (ChangeRequest) changes.next();
|
||||
switch (change.type) {
|
||||
case ChangeRequest.CHANGEOPS:
|
||||
SelectionKey key = change.socket.keyFor(this.selector);
|
||||
key.interestOps(change.ops);
|
||||
}
|
||||
}
|
||||
this.pendingChanges.clear();
|
||||
}
|
||||
|
||||
// Wait for an event one of the registered channels
|
||||
System.out.println("accepting");
|
||||
this.selector.select();
|
||||
|
||||
// Iterate over the set of keys for which events are available
|
||||
Iterator selectedKeys = this.selector.selectedKeys().iterator();
|
||||
while (selectedKeys.hasNext()) {
|
||||
SelectionKey key = (SelectionKey) selectedKeys.next();
|
||||
selectedKeys.remove();
|
||||
|
||||
if (!key.isValid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check what event is available and deal with it
|
||||
if (key.isAcceptable()) {
|
||||
System.out.println("new channel");
|
||||
this.accept(key);
|
||||
} else if (key.isReadable()) {
|
||||
System.out.println("reading");
|
||||
this.read(key);
|
||||
} else if (key.isWritable()) {
|
||||
System.out.println("writing");
|
||||
this.write(key);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void accept(SelectionKey key) throws IOException {
|
||||
// For an accept to be pending the channel must be a server socket channel.
|
||||
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
|
||||
|
||||
// Accept the connection and make it non-blocking
|
||||
SocketChannel socketChannel = serverSocketChannel.accept();
|
||||
Socket socket = socketChannel.socket();
|
||||
socketChannel.configureBlocking(false);
|
||||
|
||||
// Register the new SocketChannel with our Selector, indicating
|
||||
// we'd like to be notified when there's data waiting to be read
|
||||
socketChannel.register(this.selector, SelectionKey.OP_READ);
|
||||
}
|
||||
|
||||
private void read(SelectionKey key) throws IOException {
|
||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
||||
|
||||
// Clear out our read buffer so it's ready for new data
|
||||
this.readBuffer.clear();
|
||||
|
||||
// Attempt to read off the channel
|
||||
int numRead;
|
||||
try {
|
||||
numRead = socketChannel.read(this.readBuffer);
|
||||
} catch (IOException e) {
|
||||
// The remote forcibly closed the connection, cancel
|
||||
// the selection key and close the channel.
|
||||
key.cancel();
|
||||
socketChannel.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (numRead == -1) {
|
||||
// Remote entity shut the socket down cleanly. Do the
|
||||
// same from our end and cancel the channel.
|
||||
key.channel().close();
|
||||
key.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
// Hand the data off to our worker thread
|
||||
this.worker.processData(this, socketChannel, this.readBuffer.array(), numRead);
|
||||
}
|
||||
|
||||
private void write(SelectionKey key) throws IOException {
|
||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
||||
|
||||
synchronized (this.pendingData) {
|
||||
List queue = (List) this.pendingData.get(socketChannel);
|
||||
|
||||
// Write until there's not more data ...
|
||||
while (!queue.isEmpty()) {
|
||||
ByteBuffer buf = (ByteBuffer) queue.get(0);
|
||||
socketChannel.write(buf);
|
||||
if (buf.remaining() > 0) {
|
||||
// ... or the socket's buffer fills up
|
||||
break;
|
||||
}
|
||||
queue.remove(0);
|
||||
}
|
||||
|
||||
if (queue.isEmpty()) {
|
||||
// We wrote away all data, so we're no longer interested
|
||||
// in writing on this socket. Switch back to waiting for
|
||||
// data.
|
||||
key.interestOps(SelectionKey.OP_READ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Selector initSelector() throws IOException {
|
||||
// Create a new selector
|
||||
Selector socketSelector = SelectorProvider.provider().openSelector();
|
||||
|
||||
// Create a new non-blocking server socket channel
|
||||
this.serverChannel = ServerSocketChannel.open();
|
||||
serverChannel.configureBlocking(false);
|
||||
|
||||
// Bind the server socket to the specified address and port
|
||||
InetSocketAddress isa = new InetSocketAddress(this.hostAddress, this.port);
|
||||
serverChannel.socket().bind(isa);
|
||||
|
||||
// Register the server socket channel, indicating an interest in
|
||||
// accepting new connections
|
||||
serverChannel.register(socketSelector, SelectionKey.OP_ACCEPT);
|
||||
|
||||
return socketSelector;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
EchoWorker worker = new EchoWorker();
|
||||
new Thread(worker).start();
|
||||
new Thread(new NioServer(null, 9090, worker)).start();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package samples.niotut;
|
||||
|
||||
import org.ethereum.net.RLP;
|
||||
import org.ethereum.util.Utils;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
public class RspHandler {
|
||||
|
||||
public Queue<byte[]> packetsRecived = new LinkedList<byte[]>();
|
||||
|
||||
|
||||
public synchronized boolean handleResponse(byte[] rsp) {
|
||||
|
||||
packetsRecived.add(rsp);
|
||||
this.notify();
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized void waitForResponse() {
|
||||
|
||||
|
||||
while(packetsRecived.isEmpty()) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
while (!packetsRecived.isEmpty()) {
|
||||
|
||||
byte[] rsp = packetsRecived.remove();
|
||||
Utils.printHexStringForByteArray(rsp);
|
||||
|
||||
|
||||
if (rsp.length < 9){
|
||||
// Can't be any ether packet
|
||||
}
|
||||
|
||||
boolean noMoreMessages = false;
|
||||
|
||||
|
||||
// 22 40 08 91 - magic packet
|
||||
if ((rsp[0] & 0xFF) == 0x22 &&
|
||||
(rsp[1] & 0xFF) == 0x40 &&
|
||||
(rsp[2] & 0xFF) == 0x08 &&
|
||||
(rsp[3] & 0xFF) == 0x91 ){
|
||||
|
||||
|
||||
// Got ethereum message
|
||||
}
|
||||
|
||||
|
||||
int numMessages = 0;
|
||||
// count number of messages in the packet
|
||||
for (int i = 0; i < rsp.length - 3; ++i){
|
||||
|
||||
if ( (rsp[i + 0] & 0xFF) == 0x22 &&
|
||||
(rsp[i + 1] & 0xFF) == 0x40 &&
|
||||
(rsp[i + 2] & 0xFF) == 0x08 &&
|
||||
(rsp[i + 3] & 0xFF) == 0x91 ){
|
||||
|
||||
++numMessages;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("This packet contains: " + numMessages + " messages");
|
||||
|
||||
for (int i = 0; i < numMessages; ++i){
|
||||
|
||||
// Callc message length
|
||||
int messageLength = ((rsp[4] & 0xFF) << 24) +
|
||||
((rsp[5] & 0xFF) << 16) +
|
||||
((rsp[6] & 0xFF) << 8) +
|
||||
((rsp[7] & 0xFF));
|
||||
|
||||
byte[] msgPayload = new byte[messageLength];
|
||||
|
||||
System.out.println("payload size: " + msgPayload.length );
|
||||
System.out.println("packet size: " + messageLength );
|
||||
System.arraycopy(rsp, 8, msgPayload, 0, messageLength);
|
||||
|
||||
Utils.printHexStringForByteArray(msgPayload);
|
||||
|
||||
|
||||
|
||||
|
||||
Queue<Integer> index = new LinkedList<Integer>();
|
||||
|
||||
RLP.fullTraverse(msgPayload, 0, 0, msgPayload.length, 1, index);
|
||||
|
||||
// Message msg = MessageFactory.createMessage(msgPayload, index);
|
||||
// System.out.println("msg: " + msg);
|
||||
|
||||
// shift next message to the start of the packet array
|
||||
if (i + 1 < numMessages){
|
||||
|
||||
System.arraycopy(rsp, msgPayload.length + 8, rsp, 0, rsp.length - msgPayload.length - 8);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
package samples.niotut;
|
||||
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
class ServerDataEvent {
|
||||
public NioServer server;
|
||||
public SocketChannel socket;
|
||||
public byte[] data;
|
||||
|
||||
public ServerDataEvent(NioServer server, SocketChannel socket, byte[] data) {
|
||||
this.server = server;
|
||||
this.socket = socket;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
group Bytecode;
|
||||
|
||||
program(globals,functions) ::= <<
|
||||
.class public Wrapper
|
||||
.super java/lang/Object
|
||||
<globals>
|
||||
<functions>
|
||||
>>
|
||||
|
||||
variable(type,name) ::= ".var is <name> <type><\n>"
|
||||
|
||||
globalVariable(type,name) ::= ".field <name> <type><\n>"
|
||||
|
||||
function(type,name,args,locals,stats) ::= <<
|
||||
.method <name>(<args:{<it.type>}>)<type>
|
||||
<locals>
|
||||
<stats; separator="\n">
|
||||
return
|
||||
.end method
|
||||
>>
|
||||
|
||||
type_int() ::= "I"
|
||||
|
||||
type_char() ::= "C"
|
||||
|
||||
type_user_object(name) ::= "L<name>;"
|
||||
|
||||
parameter(type,name) ::= "<type> <name>"
|
||||
|
||||
statement(expr) ::= "<expr>"
|
||||
|
||||
statementList(locals,stats) ::= <<
|
||||
<locals>
|
||||
<stats; separator="\n">
|
||||
>>
|
||||
|
||||
forLoop(e1,e2,e3,locals,stats) ::= <<
|
||||
<e1>
|
||||
start:
|
||||
<e2>
|
||||
bf exit
|
||||
<locals>
|
||||
<stats; separator="\n">
|
||||
<e3>
|
||||
goto start
|
||||
exit:
|
||||
>>
|
||||
|
||||
assign(lhs,rhs) ::= <<
|
||||
<rhs>
|
||||
store <lhs>
|
||||
>>
|
||||
|
||||
|
||||
equals(left,right) ::= <<
|
||||
<left>
|
||||
<right>
|
||||
equals
|
||||
>>
|
||||
|
||||
lessThan(left,right) ::= <<
|
||||
<left>
|
||||
<right>
|
||||
lt
|
||||
>>
|
||||
|
||||
add(left,right) ::= <<
|
||||
<left>
|
||||
<right>
|
||||
add
|
||||
>>
|
||||
|
||||
refVar(id) ::= "push <id>"
|
||||
iconst(value) ::= "iconst <value>"
|
|
@ -0,0 +1,152 @@
|
|||
grammar CMinus;
|
||||
options {output=template;}
|
||||
|
||||
scope slist {
|
||||
List locals; // must be defined one per semicolon
|
||||
List stats;
|
||||
}
|
||||
|
||||
/*
|
||||
@slist::init {
|
||||
locals = new ArrayList();
|
||||
stats = new ArrayList();
|
||||
}
|
||||
*/
|
||||
|
||||
@header {
|
||||
package samples.stg;
|
||||
import org.antlr.stringtemplate.*;
|
||||
}
|
||||
|
||||
@lexer::header {
|
||||
package samples.stg;
|
||||
}
|
||||
|
||||
|
||||
program
|
||||
scope {
|
||||
List globals;
|
||||
List functions;
|
||||
}
|
||||
@init {
|
||||
$program::globals = new ArrayList();
|
||||
$program::functions = new ArrayList();
|
||||
}
|
||||
: declaration+
|
||||
-> program(globals={$program::globals},functions={$program::functions})
|
||||
;
|
||||
|
||||
declaration
|
||||
: variable {$program::globals.add($variable.st);}
|
||||
| f=function {$program::functions.add($f.st);}
|
||||
;
|
||||
|
||||
// ack is $function.st ambig? It can mean the rule's dyn scope or
|
||||
// the ref in this rule. Ack.
|
||||
|
||||
variable
|
||||
: type declarator ';'
|
||||
-> {$function.size()>0 && $function::name==null}?
|
||||
globalVariable(type={$type.st},name={$declarator.st})
|
||||
-> variable(type={$type.st},name={$declarator.st})
|
||||
;
|
||||
|
||||
declarator
|
||||
: ID -> {new StringTemplate($ID.text)}
|
||||
;
|
||||
|
||||
function
|
||||
scope {
|
||||
String name;
|
||||
}
|
||||
scope slist;
|
||||
@init {
|
||||
$slist::locals = new ArrayList();
|
||||
$slist::stats = new ArrayList();
|
||||
}
|
||||
: type ID {$function::name=$ID.text;}
|
||||
'(' ( p+=formalParameter ( ',' p+=formalParameter )* )? ')'
|
||||
block
|
||||
-> function(type={$type.st}, name={$function::name},
|
||||
locals={$slist::locals},
|
||||
stats={$slist::stats},
|
||||
args={$p})
|
||||
;
|
||||
|
||||
formalParameter
|
||||
: type declarator
|
||||
-> parameter(type={$type.st},name={$declarator.st})
|
||||
;
|
||||
|
||||
type
|
||||
: 'int' -> type_int()
|
||||
| 'char' -> type_char()
|
||||
| ID -> type_user_object(name={$ID.text})
|
||||
;
|
||||
|
||||
block
|
||||
: '{'
|
||||
( variable {$slist::locals.add($variable.st);} )*
|
||||
( stat {$slist::stats.add($stat.st);})*
|
||||
'}'
|
||||
;
|
||||
|
||||
stat
|
||||
scope slist;
|
||||
@init {
|
||||
$slist::locals = new ArrayList();
|
||||
$slist::stats = new ArrayList();
|
||||
}
|
||||
: forStat -> {$forStat.st}
|
||||
| expr ';' -> statement(expr={$expr.st})
|
||||
| block -> statementList(locals={$slist::locals}, stats={$slist::stats})
|
||||
| assignStat ';' -> {$assignStat.st}
|
||||
| ';' -> {new StringTemplate(";")}
|
||||
;
|
||||
|
||||
forStat
|
||||
scope slist;
|
||||
@init {
|
||||
$slist::locals = new ArrayList();
|
||||
$slist::stats = new ArrayList();
|
||||
}
|
||||
: 'for' '(' e1=assignStat ';' e2=expr ';' e3=assignStat ')' block
|
||||
-> forLoop(e1={$e1.st},e2={$e2.st},e3={$e3.st},
|
||||
locals={$slist::locals}, stats={$slist::stats})
|
||||
;
|
||||
|
||||
assignStat
|
||||
: ID '=' expr -> assign(lhs={$ID.text}, rhs={$expr.st})
|
||||
;
|
||||
|
||||
expr: condExpr -> {$condExpr.st}
|
||||
;
|
||||
|
||||
condExpr
|
||||
: a=aexpr
|
||||
( ( '==' b=aexpr -> equals(left={$a.st},right={$b.st})
|
||||
| '<' b=aexpr -> lessThan(left={$a.st},right={$b.st})
|
||||
)
|
||||
| -> {$a.st} // else just aexpr
|
||||
)
|
||||
;
|
||||
|
||||
aexpr
|
||||
: (a=atom -> {$a.st})
|
||||
( '+' b=atom -> add(left={$aexpr.st}, right={$b.st}) )*
|
||||
;
|
||||
|
||||
atom
|
||||
: ID -> refVar(id={$ID.text})
|
||||
| INT -> iconst(value={$INT.text})
|
||||
| '(' expr ')' -> {$expr.st}
|
||||
;
|
||||
|
||||
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
|
||||
;
|
||||
|
||||
INT : ('0'..'9')+
|
||||
;
|
||||
|
||||
WS : (' ' | '\t' | '\r' | '\n')+ {$channel=HIDDEN;}
|
||||
;
|
|
@ -0,0 +1,824 @@
|
|||
// $ANTLR 3.5.2 E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g 2014-04-27 13:24:16
|
||||
|
||||
package samples.stg;
|
||||
|
||||
|
||||
import org.antlr.runtime.*;
|
||||
import java.util.Stack;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public class CMinusLexer extends Lexer {
|
||||
public static final int EOF=-1;
|
||||
public static final int T__7=7;
|
||||
public static final int T__8=8;
|
||||
public static final int T__9=9;
|
||||
public static final int T__10=10;
|
||||
public static final int T__11=11;
|
||||
public static final int T__12=12;
|
||||
public static final int T__13=13;
|
||||
public static final int T__14=14;
|
||||
public static final int T__15=15;
|
||||
public static final int T__16=16;
|
||||
public static final int T__17=17;
|
||||
public static final int T__18=18;
|
||||
public static final int T__19=19;
|
||||
public static final int ID=4;
|
||||
public static final int INT=5;
|
||||
public static final int WS=6;
|
||||
|
||||
// delegates
|
||||
// delegators
|
||||
public Lexer[] getDelegates() {
|
||||
return new Lexer[] {};
|
||||
}
|
||||
|
||||
public CMinusLexer() {}
|
||||
public CMinusLexer(CharStream input) {
|
||||
this(input, new RecognizerSharedState());
|
||||
}
|
||||
public CMinusLexer(CharStream input, RecognizerSharedState state) {
|
||||
super(input,state);
|
||||
}
|
||||
@Override public String getGrammarFileName() { return "E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g"; }
|
||||
|
||||
// $ANTLR start "T__7"
|
||||
public final void mT__7() throws RecognitionException {
|
||||
try {
|
||||
int _type = T__7;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:6:6: ( '(' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:6:8: '('
|
||||
{
|
||||
match('(');
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "T__7"
|
||||
|
||||
// $ANTLR start "T__8"
|
||||
public final void mT__8() throws RecognitionException {
|
||||
try {
|
||||
int _type = T__8;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:7:6: ( ')' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:7:8: ')'
|
||||
{
|
||||
match(')');
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "T__8"
|
||||
|
||||
// $ANTLR start "T__9"
|
||||
public final void mT__9() throws RecognitionException {
|
||||
try {
|
||||
int _type = T__9;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:8:6: ( '+' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:8:8: '+'
|
||||
{
|
||||
match('+');
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "T__9"
|
||||
|
||||
// $ANTLR start "T__10"
|
||||
public final void mT__10() throws RecognitionException {
|
||||
try {
|
||||
int _type = T__10;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:9:7: ( ',' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:9:9: ','
|
||||
{
|
||||
match(',');
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "T__10"
|
||||
|
||||
// $ANTLR start "T__11"
|
||||
public final void mT__11() throws RecognitionException {
|
||||
try {
|
||||
int _type = T__11;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:10:7: ( ';' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:10:9: ';'
|
||||
{
|
||||
match(';');
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "T__11"
|
||||
|
||||
// $ANTLR start "T__12"
|
||||
public final void mT__12() throws RecognitionException {
|
||||
try {
|
||||
int _type = T__12;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:11:7: ( '<' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:11:9: '<'
|
||||
{
|
||||
match('<');
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "T__12"
|
||||
|
||||
// $ANTLR start "T__13"
|
||||
public final void mT__13() throws RecognitionException {
|
||||
try {
|
||||
int _type = T__13;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:12:7: ( '=' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:12:9: '='
|
||||
{
|
||||
match('=');
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "T__13"
|
||||
|
||||
// $ANTLR start "T__14"
|
||||
public final void mT__14() throws RecognitionException {
|
||||
try {
|
||||
int _type = T__14;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:13:7: ( '==' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:13:9: '=='
|
||||
{
|
||||
match("==");
|
||||
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "T__14"
|
||||
|
||||
// $ANTLR start "T__15"
|
||||
public final void mT__15() throws RecognitionException {
|
||||
try {
|
||||
int _type = T__15;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:14:7: ( 'char' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:14:9: 'char'
|
||||
{
|
||||
match("char");
|
||||
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "T__15"
|
||||
|
||||
// $ANTLR start "T__16"
|
||||
public final void mT__16() throws RecognitionException {
|
||||
try {
|
||||
int _type = T__16;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:15:7: ( 'for' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:15:9: 'for'
|
||||
{
|
||||
match("for");
|
||||
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "T__16"
|
||||
|
||||
// $ANTLR start "T__17"
|
||||
public final void mT__17() throws RecognitionException {
|
||||
try {
|
||||
int _type = T__17;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:16:7: ( 'int' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:16:9: 'int'
|
||||
{
|
||||
match("int");
|
||||
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "T__17"
|
||||
|
||||
// $ANTLR start "T__18"
|
||||
public final void mT__18() throws RecognitionException {
|
||||
try {
|
||||
int _type = T__18;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:17:7: ( '{' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:17:9: '{'
|
||||
{
|
||||
match('{');
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "T__18"
|
||||
|
||||
// $ANTLR start "T__19"
|
||||
public final void mT__19() throws RecognitionException {
|
||||
try {
|
||||
int _type = T__19;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:18:7: ( '}' )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:18:9: '}'
|
||||
{
|
||||
match('}');
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "T__19"
|
||||
|
||||
// $ANTLR start "ID"
|
||||
public final void mID() throws RecognitionException {
|
||||
try {
|
||||
int _type = ID;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:145:5: ( ( 'a' .. 'z' | 'A' .. 'Z' | '_' ) ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' )* )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:145:9: ( 'a' .. 'z' | 'A' .. 'Z' | '_' ) ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' )*
|
||||
{
|
||||
if ( (input.LA(1) >= 'A' && input.LA(1) <= 'Z')||input.LA(1)=='_'||(input.LA(1) >= 'a' && input.LA(1) <= 'z') ) {
|
||||
input.consume();
|
||||
}
|
||||
else {
|
||||
MismatchedSetException mse = new MismatchedSetException(null,input);
|
||||
recover(mse);
|
||||
throw mse;
|
||||
}
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:145:33: ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' )*
|
||||
loop1:
|
||||
while (true) {
|
||||
int alt1=2;
|
||||
int LA1_0 = input.LA(1);
|
||||
if ( ((LA1_0 >= '0' && LA1_0 <= '9')||(LA1_0 >= 'A' && LA1_0 <= 'Z')||LA1_0=='_'||(LA1_0 >= 'a' && LA1_0 <= 'z')) ) {
|
||||
alt1=1;
|
||||
}
|
||||
|
||||
switch (alt1) {
|
||||
case 1 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:
|
||||
{
|
||||
if ( (input.LA(1) >= '0' && input.LA(1) <= '9')||(input.LA(1) >= 'A' && input.LA(1) <= 'Z')||input.LA(1)=='_'||(input.LA(1) >= 'a' && input.LA(1) <= 'z') ) {
|
||||
input.consume();
|
||||
}
|
||||
else {
|
||||
MismatchedSetException mse = new MismatchedSetException(null,input);
|
||||
recover(mse);
|
||||
throw mse;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
break loop1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "ID"
|
||||
|
||||
// $ANTLR start "INT"
|
||||
public final void mINT() throws RecognitionException {
|
||||
try {
|
||||
int _type = INT;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:148:5: ( ( '0' .. '9' )+ )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:148:7: ( '0' .. '9' )+
|
||||
{
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:148:7: ( '0' .. '9' )+
|
||||
int cnt2=0;
|
||||
loop2:
|
||||
while (true) {
|
||||
int alt2=2;
|
||||
int LA2_0 = input.LA(1);
|
||||
if ( ((LA2_0 >= '0' && LA2_0 <= '9')) ) {
|
||||
alt2=1;
|
||||
}
|
||||
|
||||
switch (alt2) {
|
||||
case 1 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:
|
||||
{
|
||||
if ( (input.LA(1) >= '0' && input.LA(1) <= '9') ) {
|
||||
input.consume();
|
||||
}
|
||||
else {
|
||||
MismatchedSetException mse = new MismatchedSetException(null,input);
|
||||
recover(mse);
|
||||
throw mse;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
if ( cnt2 >= 1 ) break loop2;
|
||||
EarlyExitException eee = new EarlyExitException(2, input);
|
||||
throw eee;
|
||||
}
|
||||
cnt2++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "INT"
|
||||
|
||||
// $ANTLR start "WS"
|
||||
public final void mWS() throws RecognitionException {
|
||||
try {
|
||||
int _type = WS;
|
||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:151:5: ( ( ' ' | '\\t' | '\\r' | '\\n' )+ )
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:151:9: ( ' ' | '\\t' | '\\r' | '\\n' )+
|
||||
{
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:151:9: ( ' ' | '\\t' | '\\r' | '\\n' )+
|
||||
int cnt3=0;
|
||||
loop3:
|
||||
while (true) {
|
||||
int alt3=2;
|
||||
int LA3_0 = input.LA(1);
|
||||
if ( ((LA3_0 >= '\t' && LA3_0 <= '\n')||LA3_0=='\r'||LA3_0==' ') ) {
|
||||
alt3=1;
|
||||
}
|
||||
|
||||
switch (alt3) {
|
||||
case 1 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:
|
||||
{
|
||||
if ( (input.LA(1) >= '\t' && input.LA(1) <= '\n')||input.LA(1)=='\r'||input.LA(1)==' ' ) {
|
||||
input.consume();
|
||||
}
|
||||
else {
|
||||
MismatchedSetException mse = new MismatchedSetException(null,input);
|
||||
recover(mse);
|
||||
throw mse;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default :
|
||||
if ( cnt3 >= 1 ) break loop3;
|
||||
EarlyExitException eee = new EarlyExitException(3, input);
|
||||
throw eee;
|
||||
}
|
||||
cnt3++;
|
||||
}
|
||||
|
||||
_channel=HIDDEN;
|
||||
}
|
||||
|
||||
state.type = _type;
|
||||
state.channel = _channel;
|
||||
}
|
||||
finally {
|
||||
// do for sure before leaving
|
||||
}
|
||||
}
|
||||
// $ANTLR end "WS"
|
||||
|
||||
@Override
|
||||
public void mTokens() throws RecognitionException {
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:8: ( T__7 | T__8 | T__9 | T__10 | T__11 | T__12 | T__13 | T__14 | T__15 | T__16 | T__17 | T__18 | T__19 | ID | INT | WS )
|
||||
int alt4=16;
|
||||
switch ( input.LA(1) ) {
|
||||
case '(':
|
||||
{
|
||||
alt4=1;
|
||||
}
|
||||
break;
|
||||
case ')':
|
||||
{
|
||||
alt4=2;
|
||||
}
|
||||
break;
|
||||
case '+':
|
||||
{
|
||||
alt4=3;
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
{
|
||||
alt4=4;
|
||||
}
|
||||
break;
|
||||
case ';':
|
||||
{
|
||||
alt4=5;
|
||||
}
|
||||
break;
|
||||
case '<':
|
||||
{
|
||||
alt4=6;
|
||||
}
|
||||
break;
|
||||
case '=':
|
||||
{
|
||||
int LA4_7 = input.LA(2);
|
||||
if ( (LA4_7=='=') ) {
|
||||
alt4=8;
|
||||
}
|
||||
|
||||
else {
|
||||
alt4=7;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
{
|
||||
int LA4_8 = input.LA(2);
|
||||
if ( (LA4_8=='h') ) {
|
||||
int LA4_18 = input.LA(3);
|
||||
if ( (LA4_18=='a') ) {
|
||||
int LA4_21 = input.LA(4);
|
||||
if ( (LA4_21=='r') ) {
|
||||
int LA4_24 = input.LA(5);
|
||||
if ( ((LA4_24 >= '0' && LA4_24 <= '9')||(LA4_24 >= 'A' && LA4_24 <= 'Z')||LA4_24=='_'||(LA4_24 >= 'a' && LA4_24 <= 'z')) ) {
|
||||
alt4=14;
|
||||
}
|
||||
|
||||
else {
|
||||
alt4=9;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
alt4=14;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
alt4=14;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
alt4=14;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
{
|
||||
int LA4_9 = input.LA(2);
|
||||
if ( (LA4_9=='o') ) {
|
||||
int LA4_19 = input.LA(3);
|
||||
if ( (LA4_19=='r') ) {
|
||||
int LA4_22 = input.LA(4);
|
||||
if ( ((LA4_22 >= '0' && LA4_22 <= '9')||(LA4_22 >= 'A' && LA4_22 <= 'Z')||LA4_22=='_'||(LA4_22 >= 'a' && LA4_22 <= 'z')) ) {
|
||||
alt4=14;
|
||||
}
|
||||
|
||||
else {
|
||||
alt4=10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
alt4=14;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
alt4=14;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
{
|
||||
int LA4_10 = input.LA(2);
|
||||
if ( (LA4_10=='n') ) {
|
||||
int LA4_20 = input.LA(3);
|
||||
if ( (LA4_20=='t') ) {
|
||||
int LA4_23 = input.LA(4);
|
||||
if ( ((LA4_23 >= '0' && LA4_23 <= '9')||(LA4_23 >= 'A' && LA4_23 <= 'Z')||LA4_23=='_'||(LA4_23 >= 'a' && LA4_23 <= 'z')) ) {
|
||||
alt4=14;
|
||||
}
|
||||
|
||||
else {
|
||||
alt4=11;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
alt4=14;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
alt4=14;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case '{':
|
||||
{
|
||||
alt4=12;
|
||||
}
|
||||
break;
|
||||
case '}':
|
||||
{
|
||||
alt4=13;
|
||||
}
|
||||
break;
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'G':
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'J':
|
||||
case 'K':
|
||||
case 'L':
|
||||
case 'M':
|
||||
case 'N':
|
||||
case 'O':
|
||||
case 'P':
|
||||
case 'Q':
|
||||
case 'R':
|
||||
case 'S':
|
||||
case 'T':
|
||||
case 'U':
|
||||
case 'V':
|
||||
case 'W':
|
||||
case 'X':
|
||||
case 'Y':
|
||||
case 'Z':
|
||||
case '_':
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
{
|
||||
alt4=14;
|
||||
}
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
{
|
||||
alt4=15;
|
||||
}
|
||||
break;
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case ' ':
|
||||
{
|
||||
alt4=16;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NoViableAltException nvae =
|
||||
new NoViableAltException("", 4, 0, input);
|
||||
throw nvae;
|
||||
}
|
||||
switch (alt4) {
|
||||
case 1 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:10: T__7
|
||||
{
|
||||
mT__7();
|
||||
|
||||
}
|
||||
break;
|
||||
case 2 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:15: T__8
|
||||
{
|
||||
mT__8();
|
||||
|
||||
}
|
||||
break;
|
||||
case 3 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:20: T__9
|
||||
{
|
||||
mT__9();
|
||||
|
||||
}
|
||||
break;
|
||||
case 4 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:25: T__10
|
||||
{
|
||||
mT__10();
|
||||
|
||||
}
|
||||
break;
|
||||
case 5 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:31: T__11
|
||||
{
|
||||
mT__11();
|
||||
|
||||
}
|
||||
break;
|
||||
case 6 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:37: T__12
|
||||
{
|
||||
mT__12();
|
||||
|
||||
}
|
||||
break;
|
||||
case 7 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:43: T__13
|
||||
{
|
||||
mT__13();
|
||||
|
||||
}
|
||||
break;
|
||||
case 8 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:49: T__14
|
||||
{
|
||||
mT__14();
|
||||
|
||||
}
|
||||
break;
|
||||
case 9 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:55: T__15
|
||||
{
|
||||
mT__15();
|
||||
|
||||
}
|
||||
break;
|
||||
case 10 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:61: T__16
|
||||
{
|
||||
mT__16();
|
||||
|
||||
}
|
||||
break;
|
||||
case 11 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:67: T__17
|
||||
{
|
||||
mT__17();
|
||||
|
||||
}
|
||||
break;
|
||||
case 12 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:73: T__18
|
||||
{
|
||||
mT__18();
|
||||
|
||||
}
|
||||
break;
|
||||
case 13 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:79: T__19
|
||||
{
|
||||
mT__19();
|
||||
|
||||
}
|
||||
break;
|
||||
case 14 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:85: ID
|
||||
{
|
||||
mID();
|
||||
|
||||
}
|
||||
break;
|
||||
case 15 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:88: INT
|
||||
{
|
||||
mINT();
|
||||
|
||||
}
|
||||
break;
|
||||
case 16 :
|
||||
// E:\\WorkingArea\\ethereumJ\\src\\main\\java\\samples\\stg\\CMinus.g:1:92: WS
|
||||
{
|
||||
mWS();
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package samples.stg;
|
||||
|
||||
/**
|
||||
* www.ethereumJ.com
|
||||
* User: Roman Mandeleil
|
||||
* Created on: 25/04/14 17:06
|
||||
*/
|
||||
public class GenParser {
|
||||
|
||||
|
||||
public static void main(String args[]){
|
||||
|
||||
String userDir = System.getProperty("user.dir");
|
||||
org.antlr.Tool.main(new String[]{userDir + "\\src\\main\\java\\samples\\stg\\CMinus.g"});
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
group Java;
|
||||
|
||||
program(globals,functions) ::= <<
|
||||
class Wrapper {
|
||||
<globals; separator="\n">
|
||||
<functions; separator="\n">
|
||||
}
|
||||
>>
|
||||
|
||||
variable(type,name) ::= "<type> <name>;"
|
||||
|
||||
globalVariable ::= variable
|
||||
|
||||
function(type,name,args,locals,stats) ::= <<
|
||||
<type> <name>(<args; separator=", ">) {
|
||||
<locals; separator="\n">
|
||||
<stats; separator="\n">
|
||||
}
|
||||
>>
|
||||
|
||||
type_int() ::= "int"
|
||||
|
||||
type_char() ::= "char"
|
||||
|
||||
type_user_object(name) ::= "<name>"
|
||||
|
||||
parameter(type,name) ::= "<type> <name>"
|
||||
|
||||
statement(expr) ::= "<expr>;"
|
||||
|
||||
statementList(locals,stats) ::= <<
|
||||
{
|
||||
<locals; separator="\n">
|
||||
<stats; separator="\n">
|
||||
}<\n>
|
||||
>>
|
||||
|
||||
forLoop(e1,e2,e3,locals,stats) ::= <<
|
||||
for (<e1> <e2>; <e3>) {
|
||||
<locals; separator="\n">
|
||||
<stats; separator="\n">
|
||||
}
|
||||
>>
|
||||
|
||||
assign(lhs,rhs) ::= "<lhs> = <rhs>;"
|
||||
|
||||
equals(left,right) ::= "<left> == <right>"
|
||||
|
||||
lessThan(left,right) ::= "<left> \< <right>"
|
||||
|
||||
add(left,right) ::= "<left> + <right>"
|
||||
|
||||
refVar(id) ::= "<id>"
|
||||
|
||||
iconst(value) ::= "<value>"
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
package samples.stg;
|
||||
import java.io.*;
|
||||
import org.antlr.runtime.*;
|
||||
import org.antlr.stringtemplate.*;
|
||||
import org.antlr.stringtemplate.language.*;
|
||||
|
||||
public class Main {
|
||||
public static StringTemplateGroup templates;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String templateFileName;
|
||||
|
||||
String userDir = System.getProperty("user.dir");
|
||||
|
||||
templateFileName = userDir + "\\src\\main\\java\\samples\\stg\\Bytecode.stg";
|
||||
templates = new StringTemplateGroup(new FileReader(templateFileName),
|
||||
AngleBracketTemplateLexer.class);
|
||||
|
||||
String srcFile = userDir + "\\src\\main\\java\\samples\\stg\\input";
|
||||
|
||||
CharStream input = new ANTLRFileStream(srcFile);
|
||||
CMinusLexer lexer = new CMinusLexer(input);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
CMinusParser parser = new CMinusParser(tokens);
|
||||
parser.setTemplateLib(templates);
|
||||
RuleReturnScope r = parser.program();
|
||||
System.out.println(r.getTemplate().toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
group Python;
|
||||
|
||||
program(globals,functions) ::= <<
|
||||
<functions; separator="\n">
|
||||
>>
|
||||
|
||||
variable(type,name) ::= " "
|
||||
|
||||
globalVariable ::= variable
|
||||
|
||||
function(type,name,args,locals,stats) ::= <<
|
||||
def <name>(<args; separator=", ">):
|
||||
<stats>
|
||||
>>
|
||||
|
||||
type_int() ::= "int"
|
||||
|
||||
type_char() ::= "char"
|
||||
|
||||
type_user_object(name) ::= "<name>"
|
||||
|
||||
parameter(type,name) ::= "<name>"
|
||||
|
||||
statement(expr) ::= "<expr>"
|
||||
|
||||
statementList(locals,stats) ::= <<
|
||||
<stats; separator="\n">
|
||||
>>
|
||||
|
||||
// python has a weird FOR, use a WHILE. :)
|
||||
forLoop(e1,e2,e3,locals,stats) ::= <<
|
||||
<e1>
|
||||
while ( <e2> ):
|
||||
<stats; separator="\n">
|
||||
<e3>
|
||||
>>
|
||||
|
||||
assign(lhs,rhs) ::= "<lhs> = <rhs>"
|
||||
|
||||
equals(left,right) ::= "<left> == <right>"
|
||||
|
||||
lessThan(left,right) ::= "<left> \< <right>"
|
||||
|
||||
add(left,right) ::= "<left> + <right>"
|
||||
|
||||
refVar(id) ::= "<id>"
|
||||
|
||||
iconst(value) ::= "<value>"
|
|
@ -0,0 +1,7 @@
|
|||
Java.stg
|
||||
Bytecode.stg
|
||||
Python.stg
|
||||
Main.java
|
||||
CMinus.g
|
||||
input
|
||||
output
|
|
@ -0,0 +1,9 @@
|
|||
char c;
|
||||
int x;
|
||||
int foo(int y, char d) {
|
||||
int i;
|
||||
for (i=0; i<3; i=i+1) {
|
||||
x=3;
|
||||
y=5;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
class Wrapper {
|
||||
char c;
|
||||
int x;
|
||||
int foo(int y, char d) {
|
||||
int i;
|
||||
for (i = 0; i < 3; i = i + 1;) {
|
||||
x = 3;
|
||||
y = 5;
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 7.9 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 69 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 959 B |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 636 B |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.2 KiB |