sbuilder-ethereum 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/VERSION +1 -0
  3. data/lib/mixer/decl_ref.rb +19 -0
  4. data/lib/mixer/domain_ref.rb +18 -0
  5. data/lib/mixer/scope.rb +92 -0
  6. data/lib/mixer/scoped.rb +17 -0
  7. data/lib/mixer/symbol_ref.rb +16 -0
  8. data/lib/mixer/type_symbol.rb +75 -0
  9. data/lib/plugin/plugin.rb +332 -0
  10. data/lib/resources/correctness/accouns_type.tla +1 -0
  11. data/lib/resources/correctness/accounts_unique.tla +2 -0
  12. data/lib/resources/correctness/accounts_valid.tla +2 -0
  13. data/lib/resources/correctness/storage_root_unique.tla +2 -0
  14. data/lib/resources/correctness/total_value.tla +1 -0
  15. data/lib/resources/eth/accounts_state.tla +2 -0
  16. data/lib/resources/eth/accounts_temp.tla +2 -0
  17. data/lib/resources/eth/address_free.tla +2 -0
  18. data/lib/resources/eth/mined_state.tla +1 -0
  19. data/lib/resources/eth/storageRoot.tla +1 -0
  20. data/lib/resources/eth/storageRoot_temp.tla +1 -0
  21. data/lib/resources/mine/mine_entry.tla +4 -0
  22. data/lib/resources/mine/mine_service.tla +22 -0
  23. data/lib/resources/operators/elementExists.tla +4 -0
  24. data/lib/resources/operators/gasPrice.tla +2 -0
  25. data/lib/resources/operators/gasValue.tla +2 -0
  26. data/lib/resources/operators/getElement.tla +5 -0
  27. data/lib/resources/operators/intrinsicGas.tla +4 -0
  28. data/lib/resources/operators/transactionGas.tla +4 -0
  29. data/lib/resources/operators/upFrontCost.tla +6 -0
  30. data/lib/resources/personal_newAccount/personal_newAccount_done.tla +14 -0
  31. data/lib/resources/personal_newAccount/personal_newAccount_entry.tla +10 -0
  32. data/lib/resources/personal_newAccount/personal_newAccount_service.tla +29 -0
  33. data/lib/resources/removed/sendTransaction_entry.tla +5 -0
  34. data/lib/resources/removed/sendTransaction_service.tla +36 -0
  35. data/lib/resources/removed/tst.tla +1 -0
  36. data/lib/resources/transaction/ethereum_service_done.tla +24 -0
  37. data/lib/resources/transaction/ethereum_service_pop.tla +24 -0
  38. data/lib/resources/transaction/ethereum_service_push.tla +14 -0
  39. data/lib/resources/transaction/ethereum_service_start.tla +13 -0
  40. data/lib/resources/transaction/status_fail.tla +1 -0
  41. data/lib/resources/transaction/status_ok.tla +1 -0
  42. data/lib/sbuilder-ethereum.rb +52 -0
  43. data/lib/sbuilder/compile.rb +163 -0
  44. data/lib/sbuilder/constants.rb +93 -0
  45. data/lib/sbuilder/exception.rb +22 -0
  46. data/lib/sbuilder/generate/sexp_processor_tla.rb +2674 -0
  47. data/lib/sbuilder/generate/tla_element_generator.rb +1206 -0
  48. data/lib/sbuilder/generate/tla_element_text.rb +703 -0
  49. data/lib/sbuilder/load.rb +119 -0
  50. data/lib/sbuilder/mustache/renderer.rb +152 -0
  51. data/lib/sbuilder/render.rb +141 -0
  52. data/lib/sbuilder/s.rb +21 -0
  53. data/lib/sbuilder/sexp_ast.rb +1378 -0
  54. data/lib/sbuilder/sexp_processor_api.rb +184 -0
  55. data/lib/sbuilder/sexp_processor_canonize.rb +326 -0
  56. data/lib/sbuilder/sexp_processor_dataflow.rb +461 -0
  57. data/lib/sbuilder/sexp_processor_ethereum.rb +127 -0
  58. data/lib/sbuilder/sexp_processor_need_to_canonize.rb +572 -0
  59. data/lib/sbuilder/sexp_processor_snippet.rb +154 -0
  60. data/lib/sbuilder/sexp_processor_symboltable1.rb +296 -0
  61. data/lib/sbuilder/sexp_processor_symboltable2.rb +175 -0
  62. data/lib/sbuilder/sexp_utils.rb +417 -0
  63. data/lib/utils/logger.rb +82 -0
  64. data/lib/utils/string_inject.rb +11 -0
  65. data/sbuilder-ethereum.gemspec +39 -0
  66. metadata +190 -0
@@ -0,0 +1 @@
1
+ accounts_type == \A e \in {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}}: e \in {{#SPEC_NAME}}definitions.Accounts{{/SPEC_NAME}}
@@ -0,0 +1,2 @@
1
+ \* Invariant: unique entries in account state variable
2
+ accounts_unique == uniqueElements( {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}}, "address" )
@@ -0,0 +1,2 @@
1
+ \* valid account must have value >= 0, and address # Nil
2
+ accounts_valid == \A a \in {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}}: a.address # Nil /\ a.balance >= 0
@@ -0,0 +1,2 @@
1
+ \* Invariant: unique entries in storageRoot state variable
2
+ storageRoot_unique == uniqueElements( {{#SPEC_NAME}}eth.storageRoot{{/SPEC_NAME}}, "address" )
@@ -0,0 +1 @@
1
+ total_value == Stable => ( {{#SPEC_NAME}}eth.mined{{/SPEC_NAME}} + SumRecordField( {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}}, "balance" ) = 0 )
@@ -0,0 +1,2 @@
1
+ \* account entries
2
+ {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}} = {};
@@ -0,0 +1,2 @@
1
+ \* account transient state
2
+ {{#SPEC_NAME}}eth.accounts_temp{{/SPEC_NAME}} = <<>>;
@@ -0,0 +1,2 @@
1
+ \* Unassigned addresses
2
+ {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}} = {{#SPEC_NAME}}domains.eth_address{{/SPEC_NAME}} \ { Nil };
@@ -0,0 +1 @@
1
+ {{#SPEC_NAME}}eth.mined{{/SPEC_NAME}} = 0;
@@ -0,0 +1 @@
1
+ {{#SPEC_NAME}}eth.storageRoot{{/SPEC_NAME}} = {};
@@ -0,0 +1 @@
1
+ {{#SPEC_NAME}}eth.storageRoot_temp{{/SPEC_NAME}} = <<>>;
@@ -0,0 +1,4 @@
1
+ macro {{#SPEC_NAME}}service_implementation.geth_mine(){{/SPEC_NAME}}( input ) {
2
+
3
+ call {{#SPEC_NAME}}eth.mine{{/SPEC_NAME}}( input );
4
+ }
@@ -0,0 +1,22 @@
1
+ procedure {{#SPEC_NAME}}eth.mine{{/SPEC_NAME}}( input ) {
2
+
3
+ {{#SPEC_NAME}}eth.mine{{/SPEC_NAME}}_enter:
4
+
5
+ \* Check that account input.etherbase exists
6
+ if ( { e \in {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}}: e.address = input.beneficiary } = {}) {
7
+ goto {{#SPEC_NAME}}eth.mine{{/SPEC_NAME}}_exit;
8
+ };
9
+
10
+ {{#SPEC_NAME}}eth.mine{{/SPEC_NAME}}_ok:
11
+
12
+ \* Update on 'account.balance' with 'input.value'
13
+ {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}} :=
14
+ { IF e.address = input.beneficiary THEN [ e EXCEPT !.balance = e.balance + input.value ] ELSE e : e \in {{#SPEC_NAME}}eth.accounts{{/SPEC_NAME}} };
15
+
16
+ \* Update total value 'mined'
17
+ {{#SPEC_NAME}}eth.mined{{/SPEC_NAME}} := {{#SPEC_NAME}}eth.mined{{/SPEC_NAME}} - input.value;
18
+
19
+ {{#SPEC_NAME}}eth.mine{{/SPEC_NAME}}_exit:
20
+ return;
21
+
22
+ }
@@ -0,0 +1,4 @@
1
+ (*
2
+ * Unique element exists
3
+ *)
4
+ elementExists( set, key, id ) == Cardinality( { e \in set : e[key] = id } ) = 1
@@ -0,0 +1,2 @@
1
+ \* Use integer math, and gasPrice is just 1
2
+ gasPrice == 0
@@ -0,0 +1,2 @@
1
+ \* @return [Integer] gas * gasPrice
2
+ gasValue( gas ) == gas * gasPrice
@@ -0,0 +1,5 @@
1
+ (*
2
+ * Return element from 'set' such that element['key'] == 'id'
3
+ * Assume 'id' unique, and element exists
4
+ *)
5
+ getElement( set, key, id ) == ( CHOOSE x \in { e \in set : e[key] = id } : TRUE )
@@ -0,0 +1,4 @@
1
+ (* Always consume at least one unit of gas
2
+ * Account must have balance >= intrinsicGas*gasPrice before execution
3
+ *)
4
+ intrinsicGas == 1
@@ -0,0 +1,4 @@
1
+ (*
2
+ * Running transaction consumes always 1 unit of gas.
3
+ *)
4
+ transactionGas == 1
@@ -0,0 +1,6 @@
1
+ (*
2
+ * Value account must hold before transaction possible to start
3
+ *
4
+ * @return [Integer] request.value + gasPrice * intrinsicGas
5
+ *)
6
+ upFrontCost( request ) == request.value + gasPrice * intrinsicGas
@@ -0,0 +1,14 @@
1
+ macro personal_newAccount_done( interface ) {
2
+
3
+ \* like ethereum_service_done( interface ) + creates eth_storageRoot
4
+
5
+
6
+ eth_storageRoot := Head(eth_storageRoot_temp) \union { [address |-> InfrastructureServiceGetResponse( "personal_newAccount()" ) ] };
7
+ eth_accounts := Head(eth_accounts_temp);
8
+ \* eth_gasUsed := Head(eth_gasUsed_temp);
9
+
10
+ eth_storageRoot_temp := <<>>;
11
+ eth_accounts_temp := <<>>;
12
+ \* eth_gasUsed_temp := <<>>;
13
+
14
+ }
@@ -0,0 +1,10 @@
1
+ macro {{#SPEC_NAME}}service_implementation.personal_newAccount(){{/SPEC_NAME}}( input ) {
2
+
3
+ \* prepare for transaction
4
+ \* print <<"TRACE>","TX-start@personal_newAccount(): push block state to stack">>;
5
+
6
+ ethereum_service_start();
7
+
8
+ call {{#SPEC_NAME}}eth.personal_newAccount{{/SPEC_NAME}}( [ codeHash |-> input.dummy, address |-> Nil ] );
9
+
10
+ }
@@ -0,0 +1,29 @@
1
+
2
+ (*
3
+ * @param [codeHash] class name, Nil for non-contract accounts
4
+ * @param [address] Nil|address to take from pools
5
+ *)
6
+ procedure {{#SPEC_NAME}}eth.personal_newAccount{{/SPEC_NAME}}( input ) {
7
+
8
+ {{#SPEC_NAME}}eth.personal_newAccount{{/SPEC_NAME}}_enter:
9
+
10
+ \* Must have NextId available in free address pool
11
+ assert( {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}} # {} );
12
+
13
+ \* Create account record in 'accounts' variable, input.dummy is default - because no input defined
14
+ {{#SPEC_NAME}}eth.accounts_temp{{/SPEC_NAME}} :=
15
+ UpdateTop( {{#SPEC_NAME}}eth.accounts_temp{{/SPEC_NAME}},
16
+ Head( {{#SPEC_NAME}}eth.accounts_temp{{/SPEC_NAME}} ) \union { [ address |-> NextId( {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}}, input.address ), balance |-> 0, codeHash |-> input.codeHash ]});
17
+
18
+ \* Set return
19
+ InfrastructureServiceReturn( "personal_newAccount()", status_OK, NextId( {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}}, input.address ) );
20
+
21
+ \* Remove 'NextId' from frees address pool
22
+ {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}} :=
23
+ {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}} \ { NextId( {{#SPEC_NAME}}eth.address_free{{/SPEC_NAME}}, input.address ) };
24
+
25
+ {{#SPEC_NAME}}eth.personal_newAccount{{/SPEC_NAME}}_exit:
26
+
27
+ return;
28
+
29
+ }
@@ -0,0 +1,5 @@
1
+ macro {{#SPEC_NAME}}service_implementation.sendTransaction(){{/SPEC_NAME}}( input ) {
2
+
3
+ call sendTransaction( input );
4
+
5
+ }
@@ -0,0 +1,36 @@
1
+ procedure sendTransaction( input ) {
2
+
3
+ sendTransaction_enter:
4
+
5
+
6
+ (* Validate send transaction
7
+ - must be transferring accross different addresses 'to' <> 'from'
8
+ - sender 'from' must have enough 'value'
9
+ *)
10
+
11
+ if (
12
+ { e \in accounts : e.aid = input.from } = {}
13
+ \/ input.from = input.to
14
+ \/ (CHOOSE x \in { e \in accounts: e.aid = input.from } : TRUE ).value < input.value
15
+ ) {
16
+
17
+ goto sendTransaction_exit;
18
+
19
+ };
20
+
21
+ sendTransaction_transaction_ok:
22
+
23
+
24
+ \* Send: 'to.value' += input.value; 'from.value' -= input.value
25
+
26
+ accounts := { e \in accounts : e.aid # input.from /\ e.aid # input.to }
27
+ \union
28
+ { [ e_to_new EXCEPT !.value = e_to_new.value + input.value ] : e_to_new \in { e_to \in accounts: e_to.aid = input.to } }
29
+ \union
30
+ { [ e_from_new EXCEPT !.value = e_from_new.value - input.value ] : e_from_new \in { e_from \in accounts: e_from.aid = input.from } }
31
+ ;
32
+
33
+ sendTransaction_exit:
34
+ return;
35
+
36
+ }
@@ -0,0 +1 @@
1
+ tst == TRUE
@@ -0,0 +1,24 @@
1
+ (*
2
+ * Interface process (called scheduled) has finished.
3
+ * Check service response status, and
4
+ * commit changes in 'eth_storageRoot' and 'eth_accounts', if success.
5
+ * In any case clear variables modeling block status because
6
+ * they are not needed anymore (after all scheduler starts a new
7
+ * round).
8
+ *
9
+ *)
10
+ macro ethereum_service_done( interface ) {
11
+
12
+ if ( InfrastructureServiceGetStatus(interface ) = TRUE ) {
13
+ \* Success commit changes to 'temp' & cleanup
14
+ {|^preferences.tla-trace|}\* {|/preferences.tla-trace|} print <<"TRACE>", "TX-end@", interface, "success: restore eth_storageRoot ">>;
15
+ {|^preferences.tla-trace|}\* {|/preferences.tla-trace|} print <<"TRACE>", "TX-end@", interface, "success: restore eth_accounts ">>;
16
+ (* {|^preferences.tla-trace|}\* {|/preferences.tla-trace|} print <<"TRACE>", "TX-end@", interface, "success: restore eth_gasUsed ">>; *)
17
+ eth_storageRoot := Head(eth_storageRoot_temp);
18
+ eth_accounts := Head(eth_accounts_temp);
19
+ \* eth_gasUsed := Head(eth_gasUsed_temp);
20
+ };
21
+ eth_storageRoot_temp := <<>>;
22
+ eth_accounts_temp := <<>>;
23
+ \* eth_gasUsed_temp := <<>>;
24
+ }
@@ -0,0 +1,24 @@
1
+ (*
2
+ * Service procedure for 'interface' has finished.
3
+ * Check status of service response.
4
+ * For success make changes in procedure permanent by propagating
5
+ * stack top to top-1..bottom.
6
+ *
7
+ * In any case pop one element from stack.
8
+ *
9
+ *)
10
+
11
+ macro ethereum_service_pop( interface ) {
12
+
13
+ if ( InfrastructureServiceGetStatus(interface ) = TRUE ) {
14
+ \* Success - propage changes, and make the permanent
15
+ eth_storageRoot_temp := PropageTopAndPop( eth_storageRoot_temp );
16
+ eth_accounts_temp := PropageTopAndPop( eth_accounts_temp );
17
+ \* eth_gasUsed_temp := PropageTopAndPop( eth_gasUsed_temp );
18
+ }
19
+ else {
20
+ eth_storageRoot_temp := Tail(eth_storageRoot_temp);
21
+ eth_accounts_temp := Tail(eth_accounts_temp);
22
+ \* eth_gasUsed_temp := Tail( eth_gasUsed_temp );
23
+ };
24
+ }
@@ -0,0 +1,14 @@
1
+ (*
2
+ * Macro called when service starts. Duplicates current
3
+ * top of stack.
4
+ *
5
+ * @see ethereum_service_start
6
+ * @see ethereum_service_done
7
+ *)
8
+ macro {{#SPEC_NAME}}framework-svc.ethereum_service_push{{/SPEC_NAME}}() {
9
+
10
+ eth_storageRoot_temp := Push( eth_storageRoot_temp, Head( eth_storageRoot_temp )) ;
11
+ eth_accounts_temp := Push( eth_accounts_temp, Head( eth_accounts_temp ));
12
+ \* eth_gasUsed_temp := Push( eth_gasUsed_temp, Head(eth_gasUsed_temp));
13
+
14
+ }
@@ -0,0 +1,13 @@
1
+ (*
2
+ * Macro called when transaction starts.
3
+ * Inializes ethreum block context to stack.
4
+ *
5
+ * @see ethereum_service_done
6
+ * @see ethereum_service_push
7
+ *)
8
+ macro {{#SPEC_NAME}}framework-svc.ethereum_service_start{{/SPEC_NAME}}() {
9
+
10
+ eth_storageRoot_temp := <<eth_storageRoot>>;
11
+ eth_accounts_temp := <<eth_accounts>>;
12
+ \* eth_gasUsed_temp := <<eth_gasUsed>>;
13
+ }
@@ -0,0 +1 @@
1
+ status_FAIL == FALSE
@@ -0,0 +1 @@
1
+ status_OK == TRUE
@@ -0,0 +1,52 @@
1
+
2
+ require 'sbuilder'
3
+
4
+ require_relative "utils/string_inject"
5
+ require_relative "utils/logger"
6
+
7
+
8
+ require_relative "sbuilder/exception"
9
+
10
+ # mixers
11
+ require_relative "mixer/type_symbol"
12
+ require_relative "mixer/symbol_ref"
13
+ require_relative "mixer/scope"
14
+ require_relative "mixer/scoped"
15
+ require_relative "mixer/decl_ref"
16
+ require_relative "mixer/domain_ref"
17
+
18
+ # constants
19
+ require_relative "sbuilder/constants"
20
+
21
+ # solidity stuff
22
+ require_relative "sbuilder/compile"
23
+ require_relative "sbuilder/load"
24
+
25
+
26
+ require_relative "sbuilder/sexp_ast"
27
+ require_relative "sbuilder/sexp_utils"
28
+
29
+ # sex processors
30
+ require_relative "sbuilder/sexp_processor_ethereum"
31
+ require_relative "sbuilder/sexp_processor_need_to_canonize"
32
+ require_relative "sbuilder/sexp_processor_canonize"
33
+ require_relative "sbuilder/sexp_processor_symboltable1"
34
+ require_relative "sbuilder/sexp_processor_symboltable2"
35
+ require_relative "sbuilder/sexp_processor_dataflow"
36
+ require_relative "sbuilder/sexp_processor_api"
37
+ require_relative "sbuilder/sexp_processor_snippet"
38
+ require_relative "sbuilder/s"
39
+
40
+ # Code generation
41
+ require_relative "sbuilder/generate/tla_element_text"
42
+ require_relative "sbuilder/generate/tla_element_generator"
43
+ require_relative "sbuilder/generate/sexp_processor_tla"
44
+
45
+
46
+ # mustache
47
+ require_relative "sbuilder/mustache/renderer"
48
+ require_relative "sbuilder/render"
49
+
50
+ # plugin && main
51
+ require_relative "plugin/plugin"
52
+
@@ -0,0 +1,163 @@
1
+ require 'open3'
2
+ module Sbuilder
3
+ module Ethereum
4
+
5
+
6
+ ##
7
+ # Compile solidity source.
8
+ #
9
+ class Compile
10
+
11
+ PROGNAME = nil # progname for logger default class name
12
+ include MyLogger # mix logger
13
+
14
+ # @attr [String] solc_command
15
+ attr_writer :solc_command
16
+
17
+ # @attr [String] solc_flags
18
+ attr_reader :solc_flags
19
+
20
+ # @attr [String] output_directory, can be configured outside
21
+ attr_accessor :output_directory
22
+
23
+ # @attr [String] compiled_ast
24
+ attr_accessor :compiledAst
25
+
26
+ # ------------------------------------------------------------------
27
+ # @!group construct & configure
28
+
29
+ def initialize( options = {} )
30
+
31
+ @options = options
32
+ @logger = getLogger( nil, options )
33
+ @logger.info "#{__method__}: initalized"
34
+
35
+ initDefaults
36
+
37
+ end
38
+
39
+ # set configuration values
40
+ def initDefaults
41
+ @output_directory ||= "tmp/solidity"
42
+ @solc_flags ||= "--combined-json ast -o #{output_directory}"
43
+ end
44
+
45
+ # @return [String] path to solc executable
46
+ def solc_command
47
+ @solc_command ||= "#{Dir.pwd}/solc/solidity/build/solc/solc"
48
+ end
49
+
50
+ # @!endgroup
51
+
52
+
53
+ # ------------------------------------------------------------------
54
+ # @!group public services
55
+
56
+ ##
57
+ # Call +solc_command+ to compile solidity source in +sourcePath+
58
+ # to create abstract syntax tree file in +compiledAst+
59
+ #
60
+ # @param [String|String:Array] soliditySource to solidity file to compile
61
+ #
62
+ def compile( soliditySource )
63
+
64
+ self.compiledAst = nil
65
+
66
+ sourcePaths = soliditySource.is_a?( Array ) ? soliditySource : [soliditySource]
67
+
68
+ # Check sourcePath & compiler command
69
+ sourcePaths.each do |sourcePath|
70
+ @logger.info "#{__method__}: solc_command=#{solc_command}, solc_flags=#{solc_flags}, sourcePath=#{sourcePath}, pwd=#{Dir.pwd}"
71
+ raise SbuilderEtherumCompileException, "Solidity source file '#{sourcePath}': no such file" unless File.exists?( sourcePath )
72
+ end
73
+ raise SbuilderEtherumCompileException, "Solidity output directory '#{output_directory}': no such directory" unless Dir.exists?( output_directory )
74
+ raise SbuilderEtherumCompileException, "Solidity compiler '#{solc_command}': executabable not found" unless which( solc_command )
75
+
76
+
77
+ # ast named after first source file, must not exist
78
+ astPath = ast_path( sourcePaths.first )
79
+ File.delete( astPath ) if File.exists?( astPath )
80
+ raise SbuilderEtherumCompileException, "Solidity ast file '#{astPath}': could not remove" if File.exists?( astPath )
81
+
82
+
83
+ cmd = "#{solc_command} #{solc_flags} #{sourcePaths.join(' ')} > #{astPath}"
84
+ @logger.info "#{__method__}: cmd:#{cmd}"
85
+ out,err,exit_status = Open3.capture3( cmd )
86
+
87
+ @logger.info "#{__method__}: out=#{out}, err=#{err}, st=#{exit_status}"
88
+ raise SbuilderEtherumCompileException, <<-EOS if exit_status != 0
89
+ Error compiling #{sourcePaths.join(',')}
90
+
91
+ Compiler : #{solc_command}
92
+ Flags : #{solc_flags}
93
+
94
+ Exit status: #{exit_status}
95
+
96
+ Stderr: #{err}
97
+
98
+ Output: #{out}
99
+
100
+ EOS
101
+
102
+
103
+ # check that ast file was created
104
+ raise SbuilderEtherumCompileException, <<-EOS unless File.exists?( astPath )
105
+ Error compiling #{sourcePaths.join(',')}
106
+
107
+ Compiler command
108
+
109
+ #{cmd}
110
+
111
+ in cwd #{Dir.getwd}
112
+
113
+ failed to create solidity ast file '#{astPath}'
114
+
115
+ EOS
116
+
117
+
118
+ # return path to compiled ast file
119
+ self.compiledAst = astPath
120
+ @logger.info "#{__method__}, compiledAst=#{compiledAst}"
121
+ compiledAst
122
+ end
123
+
124
+ # @!endgroup
125
+
126
+
127
+ # ------------------------------------------------------------------
128
+ # @!group configuration
129
+
130
+ # @return [String] path to a file in output directory
131
+ def ast_path( sourcePath )
132
+ "#{output_directory}/#{ast_file(sourcePath)}"
133
+ end
134
+
135
+
136
+ # @return [String] filename for abstract syntax tree for
137
+ # solidity source in +sourcePath+
138
+ def ast_file( sourcePath )
139
+ "#{File.basename( sourcePath, File.extname(sourcePath) )}.sol_json.ast"
140
+ end
141
+
142
+ # @!endgroup
143
+
144
+ # ------------------------------------------------------------------
145
+ # @!group utilities
146
+
147
+ # @return [Boolean] true if +cmd+ points to executable or it is
148
+ # found in PATH
149
+ def which( cmd )
150
+ File.exists?( cmd ) && File.executable?( cmd ) ||
151
+ ENV['PATH'].split(':').select do |folder|
152
+ f = "#{folder}/#{cmd}"
153
+ File.exists?(f) && File.executable?(f)
154
+ end.any?
155
+ end
156
+
157
+ # @!endgroup
158
+
159
+
160
+ end
161
+
162
+ end
163
+ end