Commit graph

212 commits

Author SHA1 Message Date
Evgenii Stratonikov
e52c39ae7e manifest: remove EntryPoint from manifest 2020-07-27 11:08:01 +03:00
Roman Khimov
3f2f0be2c2
Merge pull request #1187 from nspcc-dev/neo3/interop/post-preview2_adjustment
interop: post-preview2 adjustment
2020-07-17 13:33:29 +03:00
Anna Shaleva
fddad0b475 core: adjust System.Contract.Create interop
Part of #1055.

It should check given scripthash against manifest groups and return the
contract state as a struct (not interop interface).
2020-07-17 09:28:52 +03:00
Roman Khimov
f46ed798f0
Merge pull request #1169 from nspcc-dev/neo3/rpc/fields_names_adjustment
rpc: adjust RPC calls JSON fields
2020-07-15 18:24:54 +03:00
Anna Shaleva
5326fc587a core: rename Neo.Crypto.CheckMultisig to Neo.Crypto.CheckMultisigWithECDsaSecp256r1
Part of #918
2020-07-14 16:19:12 +03:00
Roman Khimov
db027ad9c5 vm: zero GAS means no GAS, use fee data to properly limit execution
We were accepting transactions with zero system fee, but we shouldn't do
that. Also, transaction's verification execution has to be limited by network
fee.
2020-07-14 08:37:29 +03:00
Anna Shaleva
72a6740717 rpc: adjust getcontractstate RPC-call JSON fields names
Part of #1130
2020-07-09 17:34:53 +03:00
Roman Khimov
372dd71708
Merge pull request #1108 from nspcc-dev/neo3/compiler/nef
compiler: support *.nef and *.manifest.json generation
2020-06-29 20:55:47 +03:00
Evgenii Stratonikov
8c18142e8a keys: implement PublicKeys.Copy()
Implement convenient wrapper over explicit allocation and copying.
2020-06-29 10:44:35 +03:00
Anna Shaleva
927127e5fb smartcontract: add nef file
It should match C# NEF3 specification in order to debug and deploy smart
contracts via NEO3 Blockchain Toolkit.
2020-06-29 09:15:25 +03:00
Roman Khimov
6f5a42facf smartcontract: correctly encode/decode AnyType
It might get emitted with notifications.
2020-06-24 10:22:21 +03:00
Anna Shaleva
9097a1a23d smartcontract: update (Parameter).MarshalJSON method
MarshalJSON should be defined on structure (not pointer), as we use
structures to marshal parameters (e.g. in NotificationEvent and
Invoke of RPC result package) and never use pointers for that purpose.

Also added marshalling of nil array into `[]` instead of `null` to
follow C# implementation.
2020-06-24 07:58:09 +03:00
Evgenii Stratonikov
6a2161207a smartcontract: rename ByteArray to ByteString in JSON for smartcontract parameters 2020-06-19 11:38:56 +03:00
Evgenii Stratonikov
b9e260a704 smartcontract: omit empty value in JSON for Interop/Any parameters 2020-06-19 11:38:56 +03:00
Roman Khimov
b483c38593 block/transaction: add network magic into the hash
We make it explicit in the appropriate Block/Transaction structures, not via a
singleton as C# node does. I think this approach has a bit more potential and
allows better packages reuse for different purposes.
2020-06-18 12:39:50 +03:00
Roman Khimov
a7cce3f894 smartcontract: use new VerifiableDecodable for ParameterContext
And implement it for Transaction, the only user of ParameterContext for
now. Which make correct signing/verifying possible for cases when
serialization for general transmission and signing differ.
2020-06-18 12:12:56 +03:00
Evgenii Stratonikov
7b4ca57e33 *: change address to the new format
NEO3 uses new prefix for address (53 = 0x35), thus string representations as
well as encrypted WIFs should be changed.
2020-06-17 15:58:21 +03:00
Evgenii Stratonikov
b12add5a78 smartcontract: rewrite trigger types for NEO3 2020-06-11 13:16:07 +03:00
Evgenii Stratonikov
61edc8705e smartcontract: start flags with 1
`iota` keyword is equal to the index of the declaration in the
corresponding block, thus AllowStates was 2 in our case.
2020-06-11 13:03:55 +03:00
Evgenii Stratonikov
532262827d smartcontract: add CallFlag.Has() helper 2020-06-11 13:03:55 +03:00
Evgenii Stratonikov
ebbf0321b2 smartcontract: add AllowStates call flag 2020-06-11 13:03:55 +03:00
Evgenii Stratonikov
5514b3f52f smartcontract,vm: remove DynamicInvoke feature
It doesn't exist in NEO3.
2020-06-11 10:45:25 +03:00
Evgenii Stratonikov
76a2f62fbd cli: use manifest during contract deployment 2020-06-11 10:45:25 +03:00
Evgenii Stratonikov
df958caf93 core: add Manifest to state.Contract 2020-06-11 10:45:24 +03:00
Roman Khimov
795523f5cd
Merge pull request #1013 from nspcc-dev/neo3/vm/stackitem_refactoring
vm: move StackItem to a separate package
2020-06-08 15:30:44 +03:00
Anna Shaleva
783f5ecb01 vm: move StackItem to a separate package
closes #912
2020-06-08 13:27:08 +03:00
Evgenii Stratonikov
96c2cc0322 smartcontract: marshal ByteArray and Signature in base64 2020-06-08 10:27:39 +03:00
Roman Khimov
709146f295 transaction: drop Inputs and Outputs, forget UTXO 2020-06-05 19:20:16 +03:00
Roman Khimov
21efccd300 transaction: remove type field, set Version to 0
Two changes being done here, because they require a lot of updates to
tests. Now we're back into version 0 and we only have one type of
transaction.

It also removes GetType and GetScript interops, both are obsolete in Neo 3.
2020-06-05 19:20:16 +03:00
Roman Khimov
f445f7c602 transaction: drop Contract transaction type 2020-06-05 19:20:16 +03:00
Roman Khimov
fed95e0069 smartcontract: (un)marshal AnyType value as null
Neo 3 can emit Null in its transfer notifications in `from` or `to` fields
when minting/burning tokens (unlike Neo 2 that emitted util.Uint256{} for this
case), then it gets converted to Parameter as AnyType and we have to JSONize
it somehow for proper RPC functioning.
2020-06-05 19:20:16 +03:00
Roman Khimov
03ecab5eec smartcontract: add JSON marshal/unmarshal for InteropType
We actually have to do that in order to answer getapplicationlog requests for
transactions that leave some interop items on the stack. It follows the same
logic our binary serializer/deserializes does leaving the type and stripping
the value (whatever that is).
2020-05-25 00:27:39 +03:00
Anna Shaleva
7acf5b2841 core: add SystemFee and NetworkFee to transaction
closes #831
2020-05-20 23:26:48 +03:00
Anna Shaleva
861aca1547 rpc, smartcontract: move contract metadata to smartcontract package 2020-05-04 08:37:39 +03:00
Evgenii Stratonikov
008e6eb233 vm: implement new PUSH opcodes 2020-04-23 10:52:28 +03:00
Evgenii Stratonikov
941410a840 core: change verification scripts to new format
Verification scripts now invoke Neo.Crypto.* interops instead of
CHECKSIG/VERIFY opcodes.
2020-04-20 11:55:24 +03:00
Evgenii Stratonikov
25354c44f9 core: implement NativeContract support 2020-04-16 15:55:34 +03:00
Evgenii Stratonikov
dd38e3ec3b smartcontract: add smartcontract manifest
Manifest contains all of smartcontract's metadata including
parameters, return value, permissions etc.
2020-04-16 14:05:32 +03:00
Evgenii Stratonikov
6b7a57a66f smartcontract: add Any type for parameter
It is used as a wildcard for default return type of a contract and
for a Null stack item.
2020-04-02 14:15:17 +03:00
Roman Khimov
f64aa201c7
Merge pull request #819 from nspcc-dev/fix/util160_marshalling
smartcontract: fix uint160 marshalling in smartcontract.Parameter
2020-04-01 22:04:30 +03:00
Anna Shaleva
5a62eb923e smartcontract: fix uint160 marshalling in smartcontract.Parameter
There's a bug after #785: smartcontract.Parameter of type hash160 should
be marshalled in LE (as default marshaller for uint160 does) instead of
BE, so fixed.
2020-04-01 20:48:46 +03:00
Roman Khimov
25201d480d smartcontract: simplify Array JSON marshalling 2020-04-01 19:21:00 +03:00
Roman Khimov
3dbe549a61 smartcontract: store MapType Parameter as a slice of KV pairs
Fixes #809.

Basically, there are three alternative approaches to fixing it:
 * allowing both []byte and string for ByteArrayType value
   minimal invasion into existing code, but ugly as hell and will probably
   backfire at some point
 * storing string values in ByteArrayType
   incurs quite a number of type conversions (and associated data copying),
   though note that these values are not changed usually, so dynamic
   properties of []byte are almost irrelevant here
 * storing only []byte values in ByteArrayType
   makes it impossible to use them as map keys which can be solved in several
   ways:
   - via an interface (Marshalable)
     which is good, but makes testing and comparing values in general harder,
     because of keys mismatch
   - using serialized Parameter as a key (in a string)
     which will need some additional marshaling/unmarshaling
   - converting MapType from map to a slice of key-value pairs
     not a bad idea as we don't use this map as a map really, the type
     itself is all about input/output for real VM types and this approach is
     also a bit closer to JSON representation of the Map
2020-04-01 19:21:00 +03:00
Evgenii Stratonikov
0036b3e52b random: make use or random package in tests
Also implement Bytes/Fill routines for generating byte slices.
2020-03-27 10:27:46 +03:00
Evgenii Stratonikov
9abda40171 testserdes: implement helpers for encode/decode routines
Frequently one needs to check if struct serializes/deserializes
properly. This commit implements helpers for such cases including:
1. JSON
2. io.Serializable interface
2020-03-27 10:27:46 +03:00
Evgenii Stratonikov
5f876aaeda smartcontract: do not require pointer in MarshalYAML
It is a single byte anyway.
Now `contract init` works properly.
2020-03-25 16:26:39 +03:00
Roman Khimov
751e79d480
Merge pull request #785 from nspcc-dev/feature/uint160_marshalling
util: JSONify uint160 using LE instead of BE
2020-03-24 12:41:07 +03:00
Anna Shaleva
2001a40312 util: JSONify uint160 using LE instead of BE
closes #769
2020-03-23 17:38:58 +03:00
Evgenii Stratonikov
6ac69d075e smartcontract: implement io.Serializable for Parameter 2020-03-23 16:27:47 +03:00
Evgenii Stratonikov
0f17b9be1d smartcontract: use int64 for Integer parameter value 2020-03-23 16:24:57 +03:00
Evgenii Stratonikov
9666e99a17 smartcontract: marshal Integer values to JSON-strings
It is done so in C# implementation, we better be
as compatible as possible.
Closes #770.
2020-03-18 11:58:17 +03:00
Evgenii Stratonikov
1e7b47ec05 smartcontract: always use int64 for integers
It is good when internal representation is unique.
2020-03-18 11:58:17 +03:00
Roman Khimov
bbd802681e cli: make gas parameter to deployment add gas to the base price
That's how it was intended to behave originally. One thing questionable here
is contract price (policy thing, basically) being moved to smartcontract
package, but it's probably fine for NEO 2.0 (as it won't change) and we'll
make something better for NEO 3.0.
2020-03-11 20:34:36 +03:00
Evgenii Stratonikov
b945f4346a smartcontract: marshal Arrays properly 2020-03-05 18:22:40 +03:00
Evgenii Stratonikov
85755a4628 smartcontract: implement (*ParameterContext).GetWitness()
After all signatures were accumulated it should be possible
to extract Witness for the verifiable item.
2020-03-05 09:45:33 +03:00
Evgenii Stratonikov
cd487e3ad4 smartcontract: implement (*ParameterContext).AddSignature() 2020-03-05 09:45:11 +03:00
Evgenii Stratonikov
0d419d3899 smartcontract: implement ParameterContext 2020-03-05 09:43:14 +03:00
Evgenii Stratonikov
acea3867b2 smartcontract: implement ContextItem 2020-03-04 20:01:26 +03:00
Evgenii Stratonikov
46db4e9d9d smartcontract: rename param_context.go to parameter.go 2020-03-04 20:01:26 +03:00
Evgenii Stratonikov
924d920423 smartcontract: support JSON unmarshaling of Signature param 2020-03-04 20:01:26 +03:00
Evgenii Stratonikov
b4f8d66bd3 smartcontract: allow to marshal nil parameters 2020-03-04 19:55:04 +03:00
Evgenii Stratonikov
7cde58f731 smartcontract: adjust parameter value to type properly 2020-03-04 19:49:50 +03:00
Roman Khimov
f5a1b928ce pkg: fix gofmt issues 2020-03-03 17:22:15 +03:00
Roman Khimov
e41d434a49 *: move all packages from CityOfZion to nspcc-dev 2020-03-03 17:21:42 +03:00
Evgenii Stratonikov
1264b629f1 smartcontract: parse Struct item type same way as Array 2020-03-02 18:05:26 +03:00
Roman Khimov
252a9f2f31
Merge pull request #690 from nspcc-dev/feature/getapplicationlog
rpc: implement getapplicationlog RPC
2020-03-02 17:41:32 +03:00
Anna Shaleva
7d46404e2d smartcontract: turn trigger types into Type
1) Turn trigger types from byte constants into Type
2) Add auto-generated stringer for future purposes
2020-03-02 17:25:27 +03:00
Anna Shaleva
b3621d4a86 smartcontract: remove unused structures
Removed following unused structures:
	-smartcontract.ContextItem
	-smartcontract.Signature
	-smartcontract.ParameterContext
2020-03-02 17:25:27 +03:00
Anna Shaleva
535f391550 smartcontract: add marshaller for Parameter
1) Add marshaller and tests for smartcontract.Parameter
2) Add unmarshaller and tests for missing types of smartcontract.Parameter:
	- MapType
	- BoolType
2020-03-02 17:25:27 +03:00
Anna Shaleva
648e0bb242 rpc/smartcontract: merge contract parameter types
Merged two types:
	- smartcontract.ParamType
	- rpc.StackParamType
into single one:
	- smartcontract.ParamType
as they duplicated the functionality.

NOTE: type smartcontract.MapType was added (as in C# implementation).

From now, list of supported smartcontract parameter types:
	UnknownType
	SignatureType
	BoolType
	IntegerType
	Hash160Type
	Hash256Type
	ByteArrayType
	PublicKeyType
	StringType
	ArrayType
	MapType
	InteropInterfaceType
	VoidType
2020-03-02 17:25:21 +03:00
Evgenii Stratonikov
a3dacd3b74 tests: replace t.Fatal with require where possible
This makes tests less verbose and unifies the style
they are written in.
2020-03-02 17:22:27 +03:00
Roman Khimov
6a3be6081c smartcontract: support "ByteArray" string for ByteArrayType
We actually do emit it ourselves in String()
2020-02-21 15:23:11 +03:00
Evgenii Stratonikov
eacea8bff5 smartcontract: implement json.Unmarshaler for ParamType 2020-02-20 15:52:08 +03:00
Evgenii Stratonikov
8243a8b3a7 emit: use io.BinWriter instead of bytes.Buffer 2020-02-06 18:45:37 +03:00
Evgenii Stratonikov
4d8a3a359b vm: move Emit* functions to a separate package
Also strip 'Emit' prefix because 'emit' is now
in the package name.
2020-02-06 18:45:37 +03:00
Evgenii Stratonikov
70b23076f8 network: allow single-node privnet setup 2020-01-13 18:01:20 +03:00
Roman Khimov
b246653f62 address: rename functions as per #579 comments
Make them more clear to understand.
2019-12-25 17:34:18 +03:00
Roman Khimov
e685e9bf9a address: move into its own package
Doesn't really belong to the crypto.
2019-12-25 15:22:02 +03:00
Roman Khimov
8b3080b972 io: rename Read/WriteBytes to Read/WriteB
go vet is not happy about them:
  pkg/io/binaryReader.go:92:21: method ReadByte() byte should have signature ReadByte() (byte, error)
  pkg/io/binaryWriter.go:75:21: method WriteByte(u8 byte) should have signature WriteByte(byte) error
2019-12-12 20:19:50 +03:00
Roman Khimov
54d888ba70 io: add type-specific read/write methods
This seriously improves the serialization/deserialization performance for
several reasons:
 * no time spent in `binary` reflection
 * no memory allocations being made on every read/write
 * uses fast ReadBytes everywhere it's appropriate

It also makes Fixed8 Serializable just for convenience.
2019-12-12 20:19:50 +03:00
Evgenii Stratonikov
838050f8b5 io: rename ReadBytes() to ReadVarBytes() 2019-12-09 15:00:15 +03:00
Roman Khimov
e4d821f32d
Merge pull request #546 from nspcc-dev/write-optimizations
Write optimizations
2019-12-06 19:40:38 +03:00
Roman Khimov
844491d365 *: use more efficient WriteBytes where appropriate
Before this patch on block import we could easily be spending more than 6
seconds out of 30 in Uint256 encoding for UnspentBalance, now it's completely
off the radar.
2019-12-06 18:22:21 +03:00
Evgenii Stratonikov
57efad912c util: add LE suffix to Uint160 methods 2019-12-06 12:16:55 +03:00
Vsevolod Brekelov
ff15a0acfd core: add trigger types as constants. Closes #509 2019-12-04 12:27:04 +03:00
Roman Khimov
138e125646 *: remove duplicate functions producing verification script
Drop wif.GetVerificationScript(), drop
smartcontract.CreateSignatureRedeemScript(), add GetVerificationScript()
directly to the PublicKey and use it everywhere.
2019-12-03 18:23:46 +03:00
Roman Khimov
8d4dd2d2e1 vm: move opcodes into their own package
This allows easier reuse of opcodes and in some cases allows to eliminate
dependencies on the whole vm package, like in compiler that only needs opcodes
and doesn't care about VM for any other purpose.

And yes, they're opcodes because an instruction is a whole thing with
operands, that's what context.Next() returns.
2019-12-03 18:22:14 +03:00
Roman Khimov
e63b25d5ad smartcontract: add user-facing testinvokefunction command
With a very special syntax.
2019-11-27 15:12:15 +03:00
Evgenii Stratonikov
1a08ad19aa sc: implement io.Serializable for ParamType 2019-11-14 14:20:38 +03:00
Roman Khimov
2611e9ab5c smartcontract: fix PropertyState definitions
Wrong bits were used to represent flags which is important for contracts
created via interop. Fixes contracts failing to store things:

WARN[16278] contract invocation failed                    block=3773025 err="error encountered at instruction 3435 (SYSCALL): failed to invoke syscall: contract c9d870d7857e956d82290d5df19de3133c107815 can't have storage" tx=fa695eea240b7b4dbb6f42ea6335447a764d8b629c40b7812ea3bca16b1f098d
WARN[16278] contract invocation failed                    block=3773025 err="error encountered at instruction 1279 (SYSCALL): failed to invoke syscall: contract 97210e7c98582151ceb37f9748c9a1d27d9ae6fd can't have storage" tx=0144d84038149fa0cf1f7912f7d5854fa5f3670f5b4217789c1441f9fd52d27b
2019-10-25 11:05:58 +03:00
Vsevolod Brekelov
8ee421db14 fix spelling and godoc comments 2019-10-22 17:56:03 +03:00
Vsevolod Brekelov
05ea84454c contracttest: fix err checking branch 2019-10-21 12:31:17 +03:00
Roman Khimov
c5a4cfaebe smartcontract: add CreateSignatureRedeemScript()
It's very similar to the CreateMultiSigRedeemScript() and it will be used in
interop functions.
2019-10-15 12:56:25 +03:00
Roman Khimov
238c590ddb core: fix contract state's Properties to use PropertyState
PublishTX only had one of these flags, but newer contracts (created via the
interop function) can have more and these flags are aggregated into one field
that uses PropertyState enumeration (it's used to publish contract, so
supposedly it's also a nice choice for contract state storage).
2019-10-15 12:56:25 +03:00
Roman Khimov
ceca9cdb67 core/vm: implement contract storage and script retrieval
Fixes script invocations via the APPCALL instruction. Adjust contract state
field types accordingly.
2019-10-04 16:13:39 +03:00
Roman Khimov
5bf00db2c9 io: move BinReader/BinWriter there, redo Serializable with it
The logic here is that we'll have all binary encoding/decoding done via our io
package, which simplifies error handling. This functionality doesn't belong to
util, so it's moved.

This also expands BufBinWriter with Reset() method to fit the needs of core
package.
2019-09-16 23:39:51 +03:00
Roman Khimov
aacf58c9ab util: add 'constructors' for BinReader/BinWriter
And an additional BufBinWriter to ease buffer management.
2019-09-16 23:38:48 +03:00
Roman Khimov
a9b9c9226d *: add/fix godoc comments to satisfy golint
Fixes things like:
 * exported type/method/function X should have comment or be unexported
 * comment on exported type/method/function X should be of the form "X ..."
   (with optional leading article)

Refs. #213.
2019-09-03 17:57:51 +03:00
Roman Khimov
eba83a0e31 smartcontract: use new binaryReader/Writer API from util 2019-08-28 19:45:17 +03:00
Roman Khimov
b77e533d13 crypto/wallet: move public/private key into the new keys package
And drop associated _pkg.dev remnants (refs. #307).

Original `dev` branch had two separate packages for public and private keys,
but those are so intertwined (`TestHelper` subpackage is a proof) that it's
better unite them and all associated code (like WIF and NEP-2) in one
package. This patch also:
 * creates internal `keytestcases` package to share things with wallet (maybe
   it'll be changed in some future)
 * ports some tests from `dev`
 * ports Verify() method for public key from `dev`
 * expands TestPrivateKey() with public key check
2019-08-27 17:45:51 +03:00
Roman Khimov
33c512032f vm: switch from Opcode to Instruction
Which matches the changes done in neo-storm and also make this codebase closer
to the `dev` branch (that also uses Instruction).
2019-08-14 15:40:31 +03:00
Evgeniy Kulikov
f000b76879 [FIX] Formatting and code-style (#118)
* [FIX] Formatting and code-style

- gofmt
- import resort
- prealloc slices
- simplify code

* fix vet
2019-01-25 12:20:35 +01:00
aprasolova
de45c58551 RPC invocation parameters (#106)
* added rpc.invoke and parameters marshalling

* removed debug output

* stringer and marshalling corrections

* version
2018-11-26 16:57:53 +01:00
cff42de061 Add proper field names for JSON RPC (#80) 2018-05-04 19:15:35 +02:00
Steven Jack
8ea013ab60 Incorrect import (#69)
* Update incorrect import

* Bumps version
2018-04-15 18:56:18 +02:00
Anthony De Meulemeester
94672cb9cc
Persistance (#53)
* added publish TX for backwards compat.

* lowered the prototick for faster block syncing

* print useragent on startup

* added createMultiRedeemScript for genesis block generation.

* building genesis block from scratch.

* implemented merkle tree.

* starting blockhain with generated genesis hash

* Fixed bug in unspent coin state.

* fixed broken tests after genesis block.

* removed log line.

* bumped version -> 0.34.0
2018-03-25 12:45:54 +02:00
Anthony De Meulemeester
1a1a19da7d
Smartcontract (#39)
* deleted transfer_output added asset type and transaction result to core

* removed writing 0x00 when buffer length is 0

* Refactored emit into VM package + moved tx to own package.

* implemented transaction along with claimTransaction.

* refactored naming of transaction + added decode address for uint160 types

* removed unnecessary folder and files.

* transaction/smartcontract logic

* bumped version 0.24.0
2018-03-04 14:56:49 +01:00
Anthony De Meulemeester
b6b8542caf
Compiler (#37)
* refactored structs so the scope is not needed anymore + fix passing struct in func arguments.

* implemented byte arrays and added runtime tests

* Added sc examples in compiler README + added quick nested if test.

* Updated README

* Changed import paths to interop layer
2018-03-02 16:49:10 +01:00
Anthony De Meulemeester
f3f6662fc9
Base wallet implementation (#35)
* Initial draft of the neo-go wallet

* Cleanup + more test for util package

* integrated wallet into neo-cli partially

* base wallet implementation + smartcontract code.
2018-03-02 16:24:09 +01:00
Anthony De Meulemeester
2345858238
Compiler update (basic sc ready) (#31)
* refactored structs, the scope is not needed anymore + fix passing struct in func arguments.

* implemented byte arrays and added runtime tests

* Added sc examples in compiler README + added quick nested if test.

* Updated README
2018-02-27 10:04:24 +01:00
Anthony De Meulemeester
de3395fb51
Refactor of imports + lots of sweet stuff (#30)
* implemented global variables.

* refactored imports + lots and lots of other sweet stuff + fix #28.

* Implemented the VM interop runtime API (GetTrigger, CheckWitness, ...)
2018-02-25 13:26:56 +01:00
anthdm
95a7ac1d22 bootstrapped projects folders. 2018-01-26 21:39:56 +01:00